Skip to content

Commit

Permalink
Update androidx.navigation and raamcosta.compose-destinations
Browse files Browse the repository at this point in the history
  • Loading branch information
romansavka-mq committed Oct 3, 2024
1 parent 81e6ff8 commit f487a4e
Show file tree
Hide file tree
Showing 46 changed files with 744 additions and 195 deletions.
14 changes: 7 additions & 7 deletions .codeStyleConfig/detekt-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ complexity:
TooManyFunctions:
active: true
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
thresholdInFiles: 11
thresholdInClasses: 11
thresholdInInterfaces: 11
thresholdInObjects: 11
thresholdInEnums: 11
thresholdInFiles: 15
thresholdInClasses: 15
thresholdInInterfaces: 15
thresholdInObjects: 15
thresholdInEnums: 3
ignoreDeprecated: false
ignorePrivate: false
ignoreOverridden: false
ignorePrivate: true
ignoreOverridden: true
ignoreAnnotatedFunctions: []

coroutines:
Expand Down
33 changes: 23 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
# Compose Navigator

Compose Navigator provides possibility to Control AndroidX NavController from View Model's.
Compose Navigator provides possibility to Control AndroidX NavController from View Model's.

The library facilitates the usage of a single NavHost controlled by one point of truth - Navigator. Provides a unified interface for providing results back between composables and receiving activity results.
The library facilitates the usage of a single NavHost controlled by one point of truth - Navigator. Provides a unified interface for
providing results back between composables and receiving activity results.

## Features

View Model's can use [Navigator](/navigation-runtime/src/main/kotlin/com/miquido/android/navigation/Navigator.kt) interface provided by [navigation-runtime](/navigation-runtime) artifact to:
- navigate forward to `direction` with optional `NavOptions`
View Model's can use [Navigator](/navigation-runtime/src/main/kotlin/com/miquido/android/navigation/Navigator.kt) interface provided
by [navigation-runtime](/navigation-runtime) artifact to:

- navigate forward to `route` with optional `NavOptions`
- navigate backward
- provide result data to previous backstack entry
- launch and receive activity results using `ActivityResultContract`

> **Warning**: library is designed to work with a single `NavHost`. Using nested `NavHost` is not tested and can cause unexpected behavior.
Destination routes can be identified with String or Kotlin Serializable object used
for [Navigation Kotlin DSL Type-Safety](https://developer.android.com/guide/navigation/design/type-safety).

> **Warning**: library is designed to work with a single `NavHost`. Using nested `NavHost` is not tested and can cause unexpected
> behavior.
## Setup
## Setup

Compose Navigator is available via maven central.

Expand Down Expand Up @@ -47,11 +54,11 @@ import com.miquido.android.navigation.handler.NavigationHandler
fun AppRoot() {
// ...
val navController = rememberNavController()

NavigationHandler(
navController = navController
)

NavHost(
navController = navController,
route = "root",
Expand All @@ -71,10 +78,12 @@ import com.miquido.android.navigation.viewmodel.navEntryViewModel
@Composable
fun StartScreen(
viewModel: StartViewModel = navEntryViewModel()
)
) {
}
```

> **Note**: that all remaining dependency injection configuration (like using adding `@HiltViewModel` for Hilt or declaring module with `viewModelOf` for Koin) remains same as it was.
> **Note**: that all remaining dependency injection configuration (like using adding `@HiltViewModel` for Hilt or declaring module with
`viewModelOf` for Koin) remains same as it was.

5. (**Optional**) Add integration with [Compose Destinations](https://composedestinations.rafaelcosta.xyz/)

Expand All @@ -85,12 +94,14 @@ dependencies {
```

Using this artifact provides additional kotlin extension methods for:

- `Navigator` to avoid calling `Direction#rote` and `Route#route` when using provided API.
- `NavAction`'s to allow object creation using `Direction` / `Route` directly.

## Samples

The repository contains few samples - showcasing:

- koin integration [sample-koin](/sample-koin)
- hilt integration [sample-hilt](/sample-hilt)
- **TBD** compose destination integration [sample-destinations](/sample-destinations)
Expand All @@ -105,7 +116,9 @@ Any feedback and contributions are highly appreciated!
**If you like the library, consider starring and sharing it with your colleagues.**

---

## About Miquido

- [About](https://careers.miquido.com/about-us/)
- [Careers](https://careers.miquido.com/job-offers/)
- [Internship at Miquido](https://careers.miquido.com/students/)
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ class DetektConventionPlugin : Plugin<Project> {
mainClass.set("io.gitlab.arturbosch.detekt.cli.Main")
inputs.files(fileTree("src").matching {
include("**/*.kt")
exclude("test/**/*.kt", "androidTest/**/*.kt")
})
outputs.file("build/reports/detekt-report.xml")
outputs.cacheIf { true }

args = listOf(
"--input", "src",
"--excludes", "src/test/**,src/androidTest/**",
"--config", "$rootDir/.codeStyleConfig/detekt-config.yml",
"--report", "xml:build/reports/detekt-report.xml,html:build/reports/detekt-report.html"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ class KtLintConventionPlugin : Plugin<Project> {
mainClass.set("com.pinterest.ktlint.Main")
inputs.files(fileTree("src").matching {
include("**/*.kt")
exclude("test/**/*.kt", "androidTest/**/*.kt")
})
outputs.file("build/reports/ktlint-report.xml")
outputs.cacheIf { true }

args = listOf(
"src/**/*.kt", "!src/test/**/*.kt", "!src/androidTest/**/*.kt",
"src/**/*.kt",
"--editorconfig=${rootDir}/.codeStyleConfig/.editorconfig",
"--reporter=checkstyle,output=build/reports/ktlint-report.xml",
"--reporter=plain"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class LintConventionPlugin : Plugin<Project> {
"JavaPluginLanguageLevel",
"AndroidGradlePluginVersion",
"EnsureInitializerMetadata",
"ObsoleteLintCustomCheck",
"VectorPath"
)
}
Expand Down
11 changes: 7 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ agp = "8.7.0"
androidTools = "31.7.0"
kotlin = "2.0.20"
kotlinx-coroutines = "1.9.0"
kotlin-kover = "0.8.3"
kotlinx-serialization = "1.7.3"
kotlinx-kover = "0.8.3"
androidx-compose = "1.7.3"
androidx-core = "1.13.1"
androidx-lifecycle = "2.8.6"
androidx-material = "1.7.3"
androidx-navigation = "2.7.7"
androidx-navigation = "2.8.2"
androidx-startup = "1.2.0"
androidx-test = "1.6.1"
androidx-test-ext = "1.2.1"
Expand All @@ -23,7 +24,7 @@ androidx-espresso = "3.6.1"
androidx-espresso-device = "1.0.1"
androidx-espresso-intents = "3.6.1"
androidx-uiautomator = "2.3.0"
compose-destinations = "1.10.2"
compose-destinations = "1.11.6"
hilt = "2.52"
koin = "3.5.6"
detekt = "1.23.7"
Expand All @@ -38,6 +39,7 @@ deps-catalog-updater = "0.8.4"
[libraries]
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" }
androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "androidx-compose" }
androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-material" }
androidx-compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "androidx-compose" }
Expand Down Expand Up @@ -77,7 +79,7 @@ android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", ver
android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" }
kotlin-compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-kover-gradlePlugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kotlin-kover" }
kotlin-kover-gradlePlugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kotlinx-kover" }
deps-update-scanner-gradlePlugin = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "deps-update-scanner" }
deps-catalog-updater-gradlePlugin = { module = "nl.littlerobots.vcu:plugin", version.ref = "deps-catalog-updater" }

Expand All @@ -97,6 +99,7 @@ android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
# Plugins defined by this project
android-application-convention = { id = "android-application.convention" }
Expand Down
1 change: 0 additions & 1 deletion instrumented-tests/.gitignore

This file was deleted.

3 changes: 3 additions & 0 deletions instrumented-tests/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.android.library.convention)
alias(libs.plugins.android.library.compose.convention)
alias(libs.plugins.kotlin.serialization)
}

android {
Expand Down Expand Up @@ -32,6 +33,8 @@ dependencies {
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.lifecycle.viewmodel.ktx)

implementation(libs.kotlinx.serialization.core)

debugImplementation(libs.androidx.compose.ui.test.manifest)

androidTestImplementation(libs.androidx.compose.ui.test.junit4)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,4 @@ class ActivityBackResultTest(
@JvmStatic
fun data() = listOf(false, true)
}

}
Original file line number Diff line number Diff line change
@@ -1,33 +1,16 @@
package com.miquido.android.navigation.test

import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.lifecycle.viewmodel.initializer
import com.miquido.android.navigation.Navigator
import com.miquido.android.navigation.getNavEntryId
import com.miquido.android.navigation.test.activity.ForthAndBackNavigationActivity
import com.miquido.android.navigation.test.activity.ForthAndBackNavigationActivity.Companion.DESTINATION_ROUT
import com.miquido.android.navigation.test.activity.ForthAndBackNavigationActivity.Companion.START_ROUT
import com.miquido.android.navigation.test.rules.createTestNavEntryViewModelsRule
import org.junit.Rule
import androidx.test.ext.junit.rules.ActivityScenarioRule
import org.junit.Test

class ForthAndBackNavigationTest {
abstract class ForthAndBackNavigationTest<A : ComponentActivity> {

@get:Rule(order = 0)
val navEntryViewModelsRule = createTestNavEntryViewModelsRule {
initializer {
ForthAndBackNavigationActivity.StartViewModel(Navigator(getNavigation(), getNavEntryId()))
}
initializer {
ForthAndBackNavigationActivity.DestinationViewModel(Navigator(getNavigation(), getNavEntryId()))
}
}

@get:Rule(order = 1)
val composeTestRule = createAndroidComposeRule<ForthAndBackNavigationActivity>()
abstract val composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<A>, A>

@Test
fun navigatingForthAndBackDisplaysExpectedScreens(): Unit = with(composeTestRule) {
Expand All @@ -46,6 +29,4 @@ class ForthAndBackNavigationTest {
onNodeWithText("I am `$START_ROUT` Screen!")
.assertIsDisplayed()
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.miquido.android.navigation.test

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.lifecycle.viewmodel.initializer
import com.miquido.android.navigation.Navigator
import com.miquido.android.navigation.getNavEntryId
import com.miquido.android.navigation.test.activity.ForthAndBackSerializableRoutesNavigationActivity
import com.miquido.android.navigation.test.activity.ForthAndBackSerializableRoutesNavigationActivity.DestinationViewModel
import com.miquido.android.navigation.test.activity.ForthAndBackSerializableRoutesNavigationActivity.StartViewModel
import com.miquido.android.navigation.test.rules.createTestNavEntryViewModelsRule
import org.junit.Rule

class ForthAndBackSerializableRoutesNavigationTest : ForthAndBackNavigationTest<ForthAndBackSerializableRoutesNavigationActivity>() {

@get:Rule(order = 0)
val navEntryViewModelsRule = createTestNavEntryViewModelsRule {
initializer {
StartViewModel(Navigator(getNavigation(), getNavEntryId()))
}
initializer {
DestinationViewModel(Navigator(getNavigation(), getNavEntryId()))
}
}

@get:Rule(order = 1)
override val composeTestRule = createAndroidComposeRule<ForthAndBackSerializableRoutesNavigationActivity>()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.miquido.android.navigation.test

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.lifecycle.viewmodel.initializer
import com.miquido.android.navigation.Navigator
import com.miquido.android.navigation.getNavEntryId
import com.miquido.android.navigation.test.activity.ForthAndBackStringRoutesNavigationActivity
import com.miquido.android.navigation.test.activity.ForthAndBackStringRoutesNavigationActivity.DestinationViewModel
import com.miquido.android.navigation.test.activity.ForthAndBackStringRoutesNavigationActivity.StartViewModel
import com.miquido.android.navigation.test.rules.createTestNavEntryViewModelsRule
import org.junit.Rule

class ForthAndBackStringRoutesNavigationTest : ForthAndBackNavigationTest<ForthAndBackStringRoutesNavigationActivity>() {

@get:Rule(order = 0)
val navEntryViewModelsRule = createTestNavEntryViewModelsRule {
initializer {
StartViewModel(Navigator(getNavigation(), getNavEntryId()))
}
initializer {
DestinationViewModel(Navigator(getNavigation(), getNavEntryId()))
}
}

@get:Rule(order = 1)
override val composeTestRule = createAndroidComposeRule<ForthAndBackStringRoutesNavigationActivity>()
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,22 @@
package com.miquido.android.navigation.test

import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.lifecycle.viewmodel.initializer
import androidx.test.espresso.Espresso
import androidx.test.espresso.device.DeviceInteraction.Companion.setScreenOrientation
import androidx.test.espresso.device.EspressoDevice.Companion.onDevice
import androidx.test.espresso.device.action.ScreenOrientation.LANDSCAPE
import androidx.test.espresso.device.action.ScreenOrientation.PORTRAIT
import androidx.test.espresso.device.rules.ScreenOrientationRule
import com.miquido.android.navigation.Navigator
import com.miquido.android.navigation.getNavEntryId
import com.miquido.android.navigation.test.activity.NavEntryBackResultActivity
import com.miquido.android.navigation.test.rules.createTestNavEntryViewModelsRule
import org.junit.Rule
import androidx.test.ext.junit.rules.ActivityScenarioRule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters

@RunWith(Parameterized::class)
class NavEntryBackResultTest(
abstract class NavEntryBackResultTest<A : ComponentActivity>(
private val withOrientationChange: Boolean
) {

@get:Rule(order = 0)
val navEntryViewModelsRule = createTestNavEntryViewModelsRule {
initializer {
NavEntryBackResultActivity.ReceiverViewModel(Navigator(getNavigation(), getNavEntryId()))
}
initializer {
NavEntryBackResultActivity.PublisherViewModel(Navigator(getNavigation(), getNavEntryId()))
}
}

@get:Rule(order = 1)
val composeTestRule = createAndroidComposeRule<NavEntryBackResultActivity>()

@get:Rule(order = 2)
val screenOrientationRule: ScreenOrientationRule = ScreenOrientationRule(PORTRAIT)
abstract val composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<A>, A>

@Test
fun receiverNavEntryDisplaysResultProvidedByPublisher(): Unit = with(composeTestRule) {
Expand Down Expand Up @@ -88,10 +64,4 @@ class NavEntryBackResultTest(
onNodeWithText("Publisher result: null")
.assertIsDisplayed()
}

companion object {
@Parameters
@JvmStatic
fun data() = listOf(false, true)
}
}
Loading

0 comments on commit f487a4e

Please sign in to comment.