diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 595e470dd6..ab9b27397f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -207,6 +207,9 @@ dependencies { implementation(projects.appnav) anvil(projects.anvilcodegen) + // TODO Create allServiceImpl() + implementation(projects.services.appnavstate.impl) + // https://developer.android.com/studio/write/java8-support#library-desugaring-versions coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.2") implementation(libs.appyx.core) diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index ee9a4fc238..d43e832fe9 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -48,6 +48,8 @@ dependencies { implementation(projects.tests.uitests) implementation(libs.coil) + implementation(projects.services.appnavstate.api) + testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) testImplementation(libs.molecule.runtime) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index d86d302ac7..938bb96116 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -47,8 +47,10 @@ import io.element.android.libraries.architecture.inputs import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.di.AppScope import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.MAIN_SPACE import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.di.MatrixUIBindings +import io.element.android.services.appnavstate.api.AppNavigationStateService import kotlinx.parcelize.Parcelize @ContributesNode(AppScope::class) @@ -58,6 +60,7 @@ class LoggedInFlowNode @AssistedInject constructor( private val roomListEntryPoint: RoomListEntryPoint, private val preferencesEntryPoint: PreferencesEntryPoint, private val createRoomEntryPoint: CreateRoomEntryPoint, + private val appNavigationStateService: AppNavigationStateService, ) : BackstackNode( backstack = BackStack( initialElement = NavTarget.RoomList, @@ -91,11 +94,16 @@ class LoggedInFlowNode @AssistedInject constructor( val imageLoaderFactory = bindings().loggedInImageLoaderFactory() Coil.setImageLoader(imageLoaderFactory) inputs.matrixClient.startSync() + appNavigationStateService.onNavigateToSession(inputs.matrixClient.sessionId) + // TODO We do not support Space yet, so directly navigate to main space + appNavigationStateService.onNavigateToSpace(MAIN_SPACE) }, onDestroy = { val imageLoaderFactory = bindings().notLoggedInImageLoaderFactory() Coil.setImageLoader(imageLoaderFactory) plugins().forEach { it.onFlowReleased(inputs.matrixClient) } + appNavigationStateService.onLeavingSpace() + appNavigationStateService.onLeavingSession() } ) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt index ab18c30e09..af862129dc 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt @@ -35,6 +35,7 @@ import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.services.appnavstate.api.AppNavigationStateService import kotlinx.parcelize.Parcelize import timber.log.Timber @@ -43,6 +44,7 @@ class RoomFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val messagesEntryPoint: MessagesEntryPoint, + private val appNavigationStateService: AppNavigationStateService, ) : BackstackNode( backstack = BackStack( initialElement = NavTarget.Messages, @@ -68,11 +70,13 @@ class RoomFlowNode @AssistedInject constructor( onCreate = { Timber.v("OnCreate") plugins().forEach { it.onFlowCreated(inputs.room) } + appNavigationStateService.onNavigateToRoom(inputs.room.roomId) }, onDestroy = { Timber.v("OnDestroy") inputs.room.close() plugins().forEach { it.onFlowReleased(inputs.room) } + appNavigationStateService.onLeavingRoom() } ) } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/SpaceId.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/SpaceId.kt new file mode 100644 index 0000000000..bb06d53018 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/SpaceId.kt @@ -0,0 +1,27 @@ +/* + * 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 io.element.android.libraries.matrix.api.core + +import java.io.Serializable + +@JvmInline +value class SpaceId(val value: String) : Serializable + +/** + * Value to use when no space is selected by the user. + */ +val MAIN_SPACE = SpaceId("!mainSpace") diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/ThreadId.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/ThreadId.kt new file mode 100644 index 0000000000..f1d6e13482 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/ThreadId.kt @@ -0,0 +1,22 @@ +/* + * 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 io.element.android.libraries.matrix.api.core + +import java.io.Serializable + +@JvmInline +value class ThreadId(val value: String) : Serializable diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt index e44a85786d..78956ea0f7 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt @@ -20,6 +20,8 @@ import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.SpaceId +import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.UserId const val A_USER_NAME = "alice" @@ -27,7 +29,9 @@ const val A_PASSWORD = "password" val A_USER_ID = UserId("@alice:server.org") val A_SESSION_ID = SessionId(A_USER_ID.value) +val A_SPACE_ID = SpaceId("!aSpaceId") val A_ROOM_ID = RoomId("!aRoomId") +val A_THREAD_ID = ThreadId("\$aThreadId") val AN_EVENT_ID = EventId("\$anEventId") const val A_ROOM_NAME = "A room name" diff --git a/services/appnavstate/api/build.gradle.kts b/services/appnavstate/api/build.gradle.kts new file mode 100644 index 0000000000..ef1166f13b --- /dev/null +++ b/services/appnavstate/api/build.gradle.kts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.services.appnavstate.api" +} + +dependencies { + implementation(libs.coroutines.core) + implementation(projects.libraries.matrix.api) +} diff --git a/services/appnavstate/api/src/main/kotlin/io/element/android/services/appnavstate/api/AppNavigationState.kt b/services/appnavstate/api/src/main/kotlin/io/element/android/services/appnavstate/api/AppNavigationState.kt new file mode 100644 index 0000000000..af6d1d7b0a --- /dev/null +++ b/services/appnavstate/api/src/main/kotlin/io/element/android/services/appnavstate/api/AppNavigationState.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.services.appnavstate.api + +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.SpaceId +import io.element.android.libraries.matrix.api.core.ThreadId + +sealed interface AppNavigationState { + object Root : AppNavigationState + + data class Session( + val sessionId: SessionId, + ) : AppNavigationState + + data class Space( + // Can be fake value, if no space is selected + val spaceId: SpaceId, + val parentSession: Session, + ) : AppNavigationState + + data class Room( + val roomId: RoomId, + val parentSpace: Space, + ) : AppNavigationState + + data class Thread( + val threadId: ThreadId, + val parentRoom: Room, + ) : AppNavigationState +} diff --git a/services/appnavstate/api/src/main/kotlin/io/element/android/services/appnavstate/api/AppNavigationStateService.kt b/services/appnavstate/api/src/main/kotlin/io/element/android/services/appnavstate/api/AppNavigationStateService.kt new file mode 100644 index 0000000000..c68db8afb7 --- /dev/null +++ b/services/appnavstate/api/src/main/kotlin/io/element/android/services/appnavstate/api/AppNavigationStateService.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.services.appnavstate.api + +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.SpaceId +import io.element.android.libraries.matrix.api.core.ThreadId +import kotlinx.coroutines.flow.StateFlow + +interface AppNavigationStateService { + val appNavigationStateFlow: StateFlow + + fun onNavigateToSession(sessionId: SessionId) + fun onLeavingSession() + + fun onNavigateToSpace(spaceId: SpaceId) + fun onLeavingSpace() + + fun onNavigateToRoom(roomId: RoomId) + fun onLeavingRoom() + + fun onNavigateToThread(threadId: ThreadId) + fun onLeavingThread() +} diff --git a/services/appnavstate/impl/build.gradle.kts b/services/appnavstate/impl/build.gradle.kts new file mode 100644 index 0000000000..253ddec2fb --- /dev/null +++ b/services/appnavstate/impl/build.gradle.kts @@ -0,0 +1,50 @@ +/* + * 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. + */ + +// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + id("io.element.android-library") + alias(libs.plugins.ksp) + alias(libs.plugins.anvil) +} + +anvil { + generateDaggerFactories.set(true) +} + +android { + namespace = "io.element.android.services.appnavstate.impl" +} + +dependencies { + anvil(projects.anvilcodegen) + implementation(libs.dagger) + implementation(projects.libraries.core) + implementation(projects.libraries.di) + implementation(projects.libraries.matrix.api) + implementation(projects.anvilannotations) + + implementation(libs.coroutines.core) + implementation(libs.androidx.corektx) + + api(projects.services.appnavstate.api) + + testImplementation(libs.test.junit) + testImplementation(libs.coroutines.test) + testImplementation(libs.test.truth) + testImplementation(projects.libraries.matrix.test) +} diff --git a/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt b/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt new file mode 100644 index 0000000000..4e0071cf46 --- /dev/null +++ b/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.services.appnavstate.impl + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.SpaceId +import io.element.android.libraries.matrix.api.core.ThreadId +import io.element.android.services.appnavstate.api.AppNavigationState +import io.element.android.services.appnavstate.api.AppNavigationStateService +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import timber.log.Timber +import javax.inject.Inject + +private val loggerTag = LoggerTag("Navigation") + +/** + * TODO This will maybe not support properly navigation using permalink. + */ +@ContributesBinding(AppScope::class) +@SingleIn(AppScope::class) +class DefaultAppNavigationStateService @Inject constructor() : AppNavigationStateService { + + private val currentAppNavigationState = MutableStateFlow(AppNavigationState.Root) + + override val appNavigationStateFlow: StateFlow = currentAppNavigationState + + override fun onNavigateToSession(sessionId: SessionId) { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Navigating to session $sessionId. Current state: $currentValue") + val newValue: AppNavigationState.Session = when (currentValue) { + is AppNavigationState.Session, + is AppNavigationState.Space, + is AppNavigationState.Room, + is AppNavigationState.Thread, + AppNavigationState.Root -> AppNavigationState.Session(sessionId) + } + currentAppNavigationState.value = newValue + } + + override fun onNavigateToSpace(spaceId: SpaceId) { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Navigating to space $spaceId. Current state: $currentValue") + val newValue: AppNavigationState.Space = when (currentValue) { + AppNavigationState.Root -> error("onNavigateToSession() must be called first") + is AppNavigationState.Session -> AppNavigationState.Space(spaceId, currentValue) + is AppNavigationState.Space -> AppNavigationState.Space(spaceId, currentValue.parentSession) + is AppNavigationState.Room -> AppNavigationState.Space(spaceId, currentValue.parentSpace.parentSession) + is AppNavigationState.Thread -> AppNavigationState.Space(spaceId, currentValue.parentRoom.parentSpace.parentSession) + } + currentAppNavigationState.value = newValue + } + + override fun onNavigateToRoom(roomId: RoomId) { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Navigating to room $roomId. Current state: $currentValue") + val newValue: AppNavigationState.Room = when (currentValue) { + AppNavigationState.Root -> error("onNavigateToSession() must be called first") + is AppNavigationState.Session -> error("onNavigateToSpace() must be called first") + is AppNavigationState.Space -> AppNavigationState.Room(roomId, currentValue) + is AppNavigationState.Room -> AppNavigationState.Room(roomId, currentValue.parentSpace) + is AppNavigationState.Thread -> AppNavigationState.Room(roomId, currentValue.parentRoom.parentSpace) + } + currentAppNavigationState.value = newValue + } + + override fun onNavigateToThread(threadId: ThreadId) { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Navigating to thread $threadId. Current state: $currentValue") + val newValue: AppNavigationState.Thread = when (currentValue) { + AppNavigationState.Root -> error("onNavigateToSession() must be called first") + is AppNavigationState.Session -> error("onNavigateToSpace() must be called first") + is AppNavigationState.Space -> error("onNavigateToRoom() must be called first") + is AppNavigationState.Room -> AppNavigationState.Thread(threadId, currentValue) + is AppNavigationState.Thread -> AppNavigationState.Thread(threadId, currentValue.parentRoom) + } + currentAppNavigationState.value = newValue + } + + override fun onLeavingThread() { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Leaving thread. Current state: $currentValue") + val newValue: AppNavigationState.Room = when (currentValue) { + AppNavigationState.Root -> error("onNavigateToSession() must be called first") + is AppNavigationState.Session -> error("onNavigateToSpace() must be called first") + is AppNavigationState.Space -> error("onNavigateToRoom() must be called first") + is AppNavigationState.Room -> error("onNavigateToThread() must be called first") + is AppNavigationState.Thread -> currentValue.parentRoom + } + currentAppNavigationState.value = newValue + } + + override fun onLeavingRoom() { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Leaving room. Current state: $currentValue") + val newValue: AppNavigationState.Space = when (currentValue) { + AppNavigationState.Root -> error("onNavigateToSession() must be called first") + is AppNavigationState.Session -> error("onNavigateToSpace() must be called first") + is AppNavigationState.Space -> error("onNavigateToRoom() must be called first") + is AppNavigationState.Room -> currentValue.parentSpace + is AppNavigationState.Thread -> currentValue.parentRoom.parentSpace + } + currentAppNavigationState.value = newValue + } + + override fun onLeavingSpace() { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Leaving space. Current state: $currentValue") + val newValue: AppNavigationState.Session = when (currentValue) { + AppNavigationState.Root -> error("onNavigateToSession() must be called first") + is AppNavigationState.Session -> error("onNavigateToSpace() must be called first") + is AppNavigationState.Space -> currentValue.parentSession + is AppNavigationState.Room -> currentValue.parentSpace.parentSession + is AppNavigationState.Thread -> currentValue.parentRoom.parentSpace.parentSession + } + currentAppNavigationState.value = newValue + } + + override fun onLeavingSession() { + val currentValue = currentAppNavigationState.value + Timber.tag(loggerTag.value).d("Leaving session. Current state: $currentValue") + currentAppNavigationState.value = AppNavigationState.Root + } +} diff --git a/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateServiceTest.kt b/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateServiceTest.kt new file mode 100644 index 0000000000..9162bdaf75 --- /dev/null +++ b/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateServiceTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package io.element.android.services.appnavstate.impl + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_SESSION_ID +import io.element.android.libraries.matrix.test.A_SPACE_ID +import io.element.android.libraries.matrix.test.A_THREAD_ID +import io.element.android.services.appnavstate.api.AppNavigationState +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertThrows +import org.junit.Test + +class DefaultAppNavigationStateServiceTest { + + @Test + fun testNavigation() = runTest { + val service = DefaultAppNavigationStateService() + service.onNavigateToSession(A_SESSION_ID) + service.onNavigateToSpace(A_SPACE_ID) + service.onNavigateToRoom(A_ROOM_ID) + service.onNavigateToThread(A_THREAD_ID) + assertThat(service.appNavigationStateFlow.first()).isEqualTo( + AppNavigationState.Thread( + A_THREAD_ID, + AppNavigationState.Room( + A_ROOM_ID, + AppNavigationState.Space( + A_SPACE_ID, + AppNavigationState.Session( + A_SESSION_ID + ) + ) + ) + ) + ) + } + + @Test + fun testFailure() = runTest { + val service = DefaultAppNavigationStateService() + assertThrows(IllegalStateException::class.java) { service.onNavigateToSpace(A_SPACE_ID) } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index c975591405..e28b354cf3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -65,6 +65,9 @@ include(":libraries:session-storage:api") include(":libraries:session-storage:impl") include(":libraries:session-storage:impl-memory") +include(":services:appnavstate:api") +include(":services:appnavstate:impl") + include(":features:onboarding:api") include(":features:onboarding:impl") include(":features:logout:api")