Skip to content

Latest commit

 

History

History
118 lines (94 loc) · 4.5 KB

08_using_nav_intents.md

File metadata and controls

118 lines (94 loc) · 4.5 KB

8. Abstracting navigation actions with NavIntent

Sometimes parts of your application might want to get from one place to another without knowing how to complete such action.

This is possible to achieve by using:

In this tutorial we will add a button to the welcome screen that opens DetailScreen with random item id.

We will start by declaring NavIntent and NavIntentResolver:

.nav.TutorialIntent.kt

import com.adamkobus.compose.navigation.destination.NavDestination
import com.adamkobus.compose.navigation.intent.NavIntent

object TutorialIntents {

    const val OPEN_RANDOM_ITEM_INTENT = "openRandomItem"

    fun openRandomItem(origin: NavDestination) =
        NavIntent(name = OPEN_RANDOM_ITEM_INTENT, origin = origin)
}

.nav.OpenRandomItemIntentResolver.kt

import com.adamkobus.compose.navigation.NavIntentResolver
import com.adamkobus.compose.navigation.destination.NavState
import com.adamkobus.compose.navigation.intent.NavIntent
import com.adamkobus.compose.navigation.intent.ResolveResult
import kotlin.random.Random

object OpenRandomItemIntentResolver : NavIntentResolver {
    private val random = Random.Default

    override suspend fun resolve(intent: NavIntent, navState: NavState): ResolveResult =
        intent.origin?.takeIf {
            intent.name == TutorialIntents.OPEN_RANDOM_ITEM_INTENT
        }?.let { origin ->
            // TutorialNavActionVerifier will be able to process this action properly
            // thanks to using intent's origin as source destination for created nav action
            ResolveResult.Action(origin goTo TutorialGraph.Detail arg random.nextInt())
        } ?: ResolveResult.None
}

And now we will register OpenRandomItemIntentResolver in ComposeNavigation:

.TutorialApplication.kt

@HiltAndroidApp
class TutorialApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        ComposeNavigation
            .addNavActionVerifiers(TutorialNavActionVerifier)
            .addNavIntentResolvers(OpenRandomItemIntentResolver) // added
    }
}

What's left is to actually use what we just created:

.ui.WelcomeScreen.kt

@Composable
private fun WelcomeScreenContent(interactions: WelcomeScreenInteractions = WelcomeScreenInteractions.STUB) {
    Column {
        (...)
        Spacer(modifier = Modifier.height(30.dp))
        Button(onClick = interactions.onOpenRandomItemClicked, modifier = Modifier.fillMaxWidth()) {
            Text(text = "Open random item!")
        }
    }
}

class WelcomeScreenVM {
    val interactions = WelcomeScreenInteractions(
        (...)
        onOpenRandomItemClicked = {
            viewModelScope.launch {
                navigationConsumer.offer(TutorialIntents.openRandomItem(TutorialGraph.Welcome))
            }
        }
    )
}

data class WelcomeScreenInteractions(
    (...)
    val onOpenRandomItemClicked: () -> Unit
)

With all those things in place you should be able to open a DetailScreen with a random item ID. Now, this might not look too useful here. But imagine if OpenRandomItemIntentResolver and DetailScreen lived in their own gradle module. Thanks to NavIntent, other Gradle modules could still open the DetailScreen without knowing anything other than the name of the intent.

This is useful when you're working on a project that can be compiled in different configurations with varying dependencies between feature modules.