Skip to content

Commit

Permalink
Merge pull request #54 from stslex/feature/navigation
Browse files Browse the repository at this point in the history
Refactor navigation
  • Loading branch information
stslex authored Oct 27, 2024
2 parents 21b874e + 7f5fde5 commit 932d359
Show file tree
Hide file tree
Showing 23 changed files with 535 additions and 127 deletions.
6 changes: 3 additions & 3 deletions app/src/main/java/com/stslex93/notes/ui/AppInit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.navigation.NavHostController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.stslex93.notes.core.navigation.v2.controller.NavExtrasHostController

@Composable
fun AppInit(
navController: NavHostController,
navController: NavExtrasHostController,
modifier: Modifier = Modifier
) {
val systemUiController = rememberSystemUiController()
Expand All @@ -34,7 +34,7 @@ fun AppInit(
.background(MaterialTheme.colorScheme.background)
) {
NavigationHost(
navHostController = navController,
navController = navController,
modifier = modifier
)
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/stslex93/notes/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.navigation.compose.rememberNavController
import com.stslex93.notes.core.navigation.di.NavigationComponentBuilder
import com.stslex93.notes.core.navigation.v2.controller.rememberNavExtrasController
import com.stslex93.notes.core.ui.di.MainUiApi
import com.stslex93.notes.core.ui.di.NavigationApi
import com.stslex93.notes.core.ui.theme.AppTheme
Expand All @@ -21,7 +21,7 @@ class MainActivity : AppCompatActivity(), MainUiApi {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
val navController = rememberNavController()
val navController = rememberNavExtrasController()
_navigationApi = NavigationComponentBuilder
.build(navController)
.also { api ->
Expand Down
15 changes: 6 additions & 9 deletions app/src/main/java/com/stslex93/notes/ui/NavigationHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,22 @@ package com.stslex93.notes.ui

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import com.stslex93.notes.core.navigation.model.AppDestination
import com.stslex93.notes.core.navigation.v2.compose.NavExtrasHost
import com.stslex93.notes.core.navigation.v2.controller.NavExtrasHostController
import com.stslex93.notes.feature.edit.ui.init.editGraph
import com.stslex93.notes.feature.edit_label.navigation.graph.editLabelGraph
import com.stslex93.notes.feature.home.navigation.homeGraph

@Composable
fun NavigationHost(
navHostController: NavHostController,
navController: NavExtrasHostController,
modifier: Modifier = Modifier,
startDestination: AppDestination = AppDestination.HOME
) {
NavHost(
navController = navHostController,
startDestination = startDestination.route
NavExtrasHost(
navController = navController,
) {
homeGraph(modifier)
editGraph(modifier)
editLabelGraph(modifier)
}
}
}
1 change: 1 addition & 0 deletions core/navigation/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id("notes.android.library")
id("notes.android.library.compose")
id("kotlin-parcelize")
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.stslex93.notes.core.navigation.di

import androidx.navigation.NavHostController
import com.stslex93.notes.core.navigation.v2.controller.NavExtrasHostController
import com.stslex93.notes.core.ui.di.NavigationApi
import dagger.BindsInstance
import dagger.Component
Expand All @@ -14,7 +14,7 @@ interface NavigationComponent : NavigationApi {
interface Builder {

@BindsInstance
fun controller(navHostController: NavHostController): Builder
fun controller(navController: NavExtrasHostController): Builder

fun build(): NavigationApi
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.stslex93.notes.core.navigation.di

import androidx.navigation.NavHostController
import com.stslex93.notes.core.navigation.v2.controller.NavExtrasHostController
import com.stslex93.notes.core.ui.di.NavigationApi

object NavigationComponentBuilder {

fun build(
navHostController: NavHostController
navController: NavExtrasHostController
): NavigationApi = DaggerNavigationComponent
.builder()
.controller(navHostController)
.controller(navController)
.build()
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.stslex93.notes.core.navigation.di

import com.stslex93.notes.core.navigation.navigator.NavigatorImpl
import com.stslex93.notes.core.navigation.v2.navigator.NavigatorImpl
import com.stslex93.notes.core.ui.di.Navigator
import dagger.Binds
import dagger.Module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,42 @@ package com.stslex93.notes.core.navigation.model

import com.stslex93.notes.core.ui.di.Screen

sealed class NavigationScreen : Screen {

abstract val screen: AppDestination

val screenRoute: String
get() = "${screen.route}${appArgs.argumentsForRoute}"

open val isSingleTop: Boolean
get() = false

open val appArgs: AppArguments
get() = AppArguments.Empty

data object HomeScreen : NavigationScreen() {
override val screen: AppDestination = AppDestination.HOME
override val isSingleTop: Boolean = true
}

data class EditNoteScreen(
private val noteId: Int,
private val isEdit: Boolean
) : NavigationScreen() {
override val screen: AppDestination = AppDestination.NOTE_EDIT
override val appArgs: AppArguments = AppArguments.NoteEdit(noteId, isEdit)
}

data class EditLabelScreen(
private val noteIds: Set<Int>
) : NavigationScreen() {
override val screen = AppDestination.LABEL_EDIT
override val appArgs = AppArguments.LabelEdit(noteIds)
}

data object PopBackStack : NavigationScreen() {

override val screen: AppDestination = AppDestination.UNDEFINED
override val appArgs: AppArguments = AppArguments.Empty
}
}
//sealed class NavigationScreen : Screen {
//
// abstract val screen: AppDestination
//
// val screenRoute: String
// get() = "${screen.route}${appArgs.argumentsForRoute}"
//
// open val isSingleTop: Boolean
// get() = false
//
// open val appArgs: AppArguments
// get() = AppArguments.Empty
//
// data object HomeScreen : NavigationScreen() {
// override val screen: AppDestination = AppDestination.HOME
// override val isSingleTop: Boolean = true
// }
//
// data class EditNoteScreen(
// private val noteId: Int,
// private val isEdit: Boolean
// ) : NavigationScreen() {
// override val screen: AppDestination = AppDestination.NOTE_EDIT
// override val appArgs: AppArguments = AppArguments.NoteEdit(noteId, isEdit)
// }
//
// data class EditLabelScreen(
// private val noteIds: Set<Int>
// ) : NavigationScreen() {
// override val screen = AppDestination.LABEL_EDIT
// override val appArgs = AppArguments.LabelEdit(noteIds)
// }
//
// data object PopBackStack : NavigationScreen() {
//
// override val screen: AppDestination = AppDestination.UNDEFINED
// override val appArgs: AppArguments = AppArguments.Empty
// }
//}
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
package com.stslex93.notes.core.navigation.navigator

import androidx.navigation.NavHostController
import com.stslex.aproselection.core.core.Logger
import com.stslex93.notes.core.navigation.model.NavigationScreen
import com.stslex93.notes.core.ui.di.Navigator
import com.stslex93.notes.core.ui.di.Screen
import javax.inject.Inject

class NavigatorImpl @Inject constructor(
private val navController: NavHostController
) : Navigator {

override fun invoke(screen: Screen) {
when (screen) {
is NavigationScreen.PopBackStack -> navController.popBackStack()
is NavigationScreen -> navigateScreen(screen)
else -> {
Logger.debug("unresolve navigation route", this::class.simpleName)
}
}
}

private fun navigateScreen(screen: NavigationScreen) {
val currentRoute = navController.currentDestination?.route ?: return
if (currentRoute == screen.screen.navigationRoute) return

navController.navigate(screen.screenRoute) {
if (screen.isSingleTop.not()) return@navigate

popUpTo(currentRoute) {
inclusive = true
saveState = true
}
launchSingleTop = true
}
}
}
//class NavigatorImpl @Inject constructor(
// private val navController: NavHostController
//) : Navigator {
//
// override fun invoke(screen: Screen) {
// when (screen) {
// is NavigationScreen.PopBackStack -> navController.popBackStack()
// is NavigationScreen -> navigateScreen(screen)
// else -> {
// Logger.debug("unresolve navigation route", this::class.simpleName)
// }
// }
// }
//
// private fun navigateScreen(screen: NavigationScreen) {
// val currentRoute = navController.currentDestination?.route ?: return
// if (currentRoute == screen.screen.navigationRoute) return
//
// navController.navigate(screen.screenRoute) {
// if (screen.isSingleTop.not()) return@navigate
//
// popUpTo(currentRoute) {
// inclusive = true
// saveState = true
// }
// launchSingleTop = true
// }
// }
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.stslex93.notes.core.navigation.v2

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class NoteEditArgs(
val noteId: Int,
val isEdit: Boolean
) : Parcelable
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.stslex93.notes.core.navigation.v2.compose

import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDeepLink
import androidx.navigation.NavGraphBuilder
import androidx.navigation.get
import com.stslex93.notes.core.navigation.v2.controller.ComposeNavigator
import com.stslex93.notes.core.navigation.v2.controller.Destination
import com.stslex93.notes.core.navigation.v2.screen.HostScreen

fun NavGraphBuilder.composable(
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
content: @Composable (backStackEntry: NavBackStackEntry, arguments: Bundle?) -> Unit
) {
addDestination(
Destination(provider[ComposeNavigator::class], content).apply {
this.route = route
arguments.forEach { (argumentName, argument) ->
addArgument(argumentName, argument)
}
deepLinks.forEach { deepLink ->
addDeepLink(deepLink)
}
}
)
}

inline fun <reified T : Parcelable> NavGraphBuilder.composable(
screen: HostScreen,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
crossinline content: @Composable (backStackEntry: NavBackStackEntry, arguments: T?) -> Unit
) {
composable(
route = screen.route,
arguments = arguments,
deepLinks = deepLinks,
) { backStackEntry, args ->
val data = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
args?.getParcelable(screen.key, T::class.java)
} else {
args?.getParcelable(screen.key)
}
content(backStackEntry, data)
}
}

inline fun <reified T : Parcelable> NavGraphBuilder.composable(
screen: HostScreen,
crossinline content: @Composable (data: T) -> Unit
) {
composable<T>(screen) { _, arguments ->
arguments?.let { data ->
content(data)
}
}
}
Loading

0 comments on commit 932d359

Please sign in to comment.