Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update androidx.navigation and raamcosta.compose-destinations #44

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
46 changes: 33 additions & 13 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 @@ -43,19 +50,26 @@ dependencies {
```kotlin
import com.miquido.android.navigation.handler.NavigationHandler

@kotlinx.serialization.Serializable
data object RootRoute

@kotlinx.serialization.Serializable
data object StartRoute


@Composable
fun AppRoot() {
// ...
val navController = rememberNavController()

NavigationHandler(
navController = navController
)

NavHost(
navController = navController,
route = "root",
startDestination = "start"
route = RootRoute::class, // or simple string "root"
startDestination = StartRoute // or simple string "start"
) {
// build your NavGraph
}
Expand All @@ -71,10 +85,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,27 +101,31 @@ 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)

## About

The library is in the beta stage, which means contains a core feature set commonly used.
The library contains a core feature set commonly used.
Please do try it and open issues if you find any.

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>()
}
Loading