Introduce AppNavigationStateService.
This commit is contained in:
30
services/appnavstate/api/build.gradle.kts
Normal file
30
services/appnavstate/api/build.gradle.kts
Normal file
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<AppNavigationState>
|
||||
|
||||
fun onNavigateToSession(sessionId: SessionId)
|
||||
fun onLeavingSession()
|
||||
|
||||
fun onNavigateToSpace(spaceId: SpaceId)
|
||||
fun onLeavingSpace()
|
||||
|
||||
fun onNavigateToRoom(roomId: RoomId)
|
||||
fun onLeavingRoom()
|
||||
|
||||
fun onNavigateToThread(threadId: ThreadId)
|
||||
fun onLeavingThread()
|
||||
}
|
||||
50
services/appnavstate/impl/build.gradle.kts
Normal file
50
services/appnavstate/impl/build.gradle.kts
Normal file
@@ -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)
|
||||
}
|
||||
@@ -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>(AppNavigationState.Root)
|
||||
|
||||
override val appNavigationStateFlow: StateFlow<AppNavigationState> = 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
|
||||
}
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user