diff --git a/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/test/MockUtil.kt b/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/test/MockUtil.kt new file mode 100644 index 000000000..d79a92a4c --- /dev/null +++ b/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/test/MockUtil.kt @@ -0,0 +1,21 @@ +package co.nimblehq.sample.compose.test + +import co.nimblehq.sample.compose.domain.model.Model + +object MockUtil { + + val models = listOf( + Model( + id = 1, + username = "name1", + ), + Model( + id = 2, + username = "name2", + ), + Model( + id = 3, + username = "name3", + ), + ) +} diff --git a/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreenTest.kt b/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt similarity index 72% rename from sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreenTest.kt rename to sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt index a5ce5d6ea..c5358e41a 100644 --- a/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreenTest.kt +++ b/sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt @@ -1,22 +1,29 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import androidx.activity.compose.setContent -import androidx.compose.ui.test.* +import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.rule.GrantPermissionRule -import co.nimblehq.sample.compose.domain.model.Model -import co.nimblehq.sample.compose.domain.usecase.* +import co.nimblehq.sample.compose.domain.usecase.GetModelsUseCase +import co.nimblehq.sample.compose.domain.usecase.IsFirstTimeLaunchPreferencesUseCase +import co.nimblehq.sample.compose.domain.usecase.UpdateFirstTimeLaunchPreferencesUseCase +import co.nimblehq.sample.compose.test.MockUtil import co.nimblehq.sample.compose.test.TestDispatchersProvider -import co.nimblehq.sample.compose.ui.AppDestination +import co.nimblehq.sample.compose.ui.base.BaseDestination import co.nimblehq.sample.compose.ui.screens.MainActivity +import co.nimblehq.sample.compose.ui.screens.main.MainDestination import co.nimblehq.sample.compose.ui.theme.ComposeTheme import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.flow.flowOf -import org.junit.* import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test class HomeScreenTest { @@ -36,13 +43,11 @@ class HomeScreenTest { private val mockUpdateFirstTimeLaunchPreferencesUseCase: UpdateFirstTimeLaunchPreferencesUseCase = mockk() private lateinit var viewModel: HomeViewModel - private var expectedAppDestination: AppDestination? = null + private var expectedDestination: BaseDestination? = null @Before fun setUp() { - every { mockGetModelsUseCase() } returns flowOf( - listOf(Model(1), Model(2), Model(3)) - ) + every { mockGetModelsUseCase() } returns flowOf(MockUtil.models) every { mockIsFirstTimeLaunchPreferencesUseCase() } returns flowOf(false) viewModel = HomeViewModel( @@ -69,7 +74,7 @@ class HomeScreenTest { fun when_clicking_on_a_list_item__it_navigates_to_Second_screen() = initComposable { onNodeWithText("1").performClick() - assertEquals(expectedAppDestination, AppDestination.Second) + assertEquals(expectedDestination, MainDestination.Second) } private fun initComposable( @@ -79,7 +84,7 @@ class HomeScreenTest { ComposeTheme { HomeScreen( viewModel = viewModel, - navigator = { destination -> expectedAppDestination = destination } + navigator = { destination -> expectedDestination = destination } ) } } diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppDestination.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppDestination.kt index f4c4adc1e..325e9c7cd 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppDestination.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppDestination.kt @@ -1,39 +1,10 @@ package co.nimblehq.sample.compose.ui -import androidx.navigation.NamedNavArgument -import androidx.navigation.NavType -import androidx.navigation.navArgument -import co.nimblehq.sample.compose.ui.models.UiModel +import co.nimblehq.sample.compose.ui.base.BaseDestination -const val KeyId = "id" -const val KeyModel = "model" +sealed class AppDestination { -sealed class AppDestination(val route: String = "") { + object RootNavGraph : BaseDestination("rootNavGraph") - open val arguments: List = emptyList() - - open var destination: String = route - - open var parcelableArgument: Pair = "" to null - - object Up : AppDestination() - - object Home : AppDestination("home") - - object Second : AppDestination("second/{$KeyId}") { - - override val arguments = listOf( - navArgument(KeyId) { type = NavType.StringType } - ) - - fun createRoute(id: String) = apply { - destination = "second/$id" - } - } - - object Third : AppDestination("third") { - fun addParcel(value: UiModel) = apply { - parcelableArgument = KeyModel to value - } - } + object MainNavGraph : BaseDestination("mainNavGraph") } diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppNavGraph.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppNavGraph.kt new file mode 100644 index 000000000..fe41f58a7 --- /dev/null +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppNavGraph.kt @@ -0,0 +1,55 @@ +package co.nimblehq.sample.compose.ui + +import androidx.compose.runtime.Composable +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavDeepLink +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import co.nimblehq.sample.compose.ui.base.BaseDestination +import co.nimblehq.sample.compose.ui.screens.main.mainNavGraph + +@Composable +fun AppNavigation( + navController: NavHostController, +) { + NavHost( + navController = navController, + route = AppDestination.RootNavGraph.route, + startDestination = AppDestination.MainNavGraph.destination + ) { + mainNavGraph(navController = navController) + } +} + +fun NavGraphBuilder.composable( + destination: BaseDestination, + deepLinks: List = emptyList(), + content: @Composable (NavBackStackEntry) -> Unit, +) { + composable( + route = destination.route, + arguments = destination.arguments, + deepLinks = deepLinks, + content = content + ) +} + +/** + * Navigate to provided [BaseDestination] with a Pair of key value String and Data [parcel] + * Caution to use this method. This method use savedStateHandle to store the Parcelable data. + * When previousBackstackEntry is popped out from navigation stack, savedStateHandle will return null and cannot retrieve data. + * eg.Login -> Home, the Login screen will be popped from the back-stack on logging in successfully. + */ +fun NavHostController.navigate(destination: BaseDestination, parcel: Pair? = null) { + when (destination) { + is BaseDestination.Up -> navigateUp() + else -> { + parcel?.let { (key, value) -> + currentBackStackEntry?.savedStateHandle?.set(key, value) + } + navigate(route = destination.destination) + } + } +} diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppNavigation.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppNavigation.kt deleted file mode 100644 index 2a20e4621..000000000 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/AppNavigation.kt +++ /dev/null @@ -1,78 +0,0 @@ -package co.nimblehq.sample.compose.ui - -import androidx.compose.runtime.Composable -import androidx.navigation.NavBackStackEntry -import androidx.navigation.NavDeepLink -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.rememberNavController -import co.nimblehq.sample.compose.ui.models.UiModel -import co.nimblehq.sample.compose.ui.screens.home.HomeScreen -import co.nimblehq.sample.compose.ui.screens.second.SecondScreen -import co.nimblehq.sample.compose.ui.screens.third.ThirdScreen - -@Composable -fun AppNavigation( - navController: NavHostController = rememberNavController(), - startDestination: String = AppDestination.Home.destination -) { - NavHost( - navController = navController, - startDestination = startDestination - ) { - composable(destination = AppDestination.Home) { - HomeScreen( - navigator = { destination -> - navController.navigate(destination, destination.parcelableArgument) - } - ) - } - - composable(destination = AppDestination.Second) { backStackEntry -> - SecondScreen( - navigator = { destination -> navController.navigate(destination) }, - id = backStackEntry.arguments?.getString(KeyId).orEmpty() - ) - } - - composable(destination = AppDestination.Third) { - ThirdScreen( - navigator = { destination -> navController.navigate(destination) }, - model = navController.previousBackStackEntry?.savedStateHandle?.get(KeyModel) - ) - } - } -} - -private fun NavGraphBuilder.composable( - destination: AppDestination, - deepLinks: List = emptyList(), - content: @Composable (NavBackStackEntry) -> Unit -) { - composable( - route = destination.route, - arguments = destination.arguments, - deepLinks = deepLinks, - content = content - ) -} - -/** - * Navigate to provided [AppDestination] with a Pair of key value String and Data [parcel] - * Caution to use this method. This method use savedStateHandle to store the Parcelable data. - * When previousBackstackEntry is popped out from navigation stack, savedStateHandle will return null and cannot retrieve data. - * eg.Login -> Home, the Login screen will be popped from the back-stack on logging in successfully. - */ -private fun NavHostController.navigate(appDestination: AppDestination, parcel: Pair? = null) { - when (appDestination) { - is AppDestination.Up -> navigateUp() - else -> { - parcel?.let { (key, value) -> - currentBackStackEntry?.savedStateHandle?.set(key, value) - } - navigate(route = appDestination.destination) - } - } -} diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseDestination.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseDestination.kt new file mode 100644 index 000000000..e7f3fe7ff --- /dev/null +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseDestination.kt @@ -0,0 +1,14 @@ +package co.nimblehq.sample.compose.ui.base + +import androidx.navigation.NamedNavArgument + +abstract class BaseDestination(val route: String = "") { + + open val arguments: List = emptyList() + + open var destination: String = route + + open var parcelableArgument: Pair = "" to null + + object Up : BaseDestination() +} diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseViewModel.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseViewModel.kt index e787f7676..ad7649708 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseViewModel.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/base/BaseViewModel.kt @@ -2,7 +2,6 @@ package co.nimblehq.sample.compose.ui.base import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import co.nimblehq.sample.compose.ui.AppDestination import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlin.coroutines.CoroutineContext @@ -19,7 +18,7 @@ abstract class BaseViewModel : ViewModel() { protected val _error = MutableSharedFlow() val error = _error.asSharedFlow() - protected val _navigator = MutableSharedFlow() + protected val _navigator = MutableSharedFlow() val navigator = _navigator.asSharedFlow() /** diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/AppBar.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/common/AppBar.kt similarity index 94% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/AppBar.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/common/AppBar.kt index ae9289870..7ca100ee4 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/AppBar.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/common/AppBar.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens +package co.nimblehq.sample.compose.ui.common import androidx.annotation.StringRes import androidx.compose.material.Text diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt index 85e28ba2a..28a6ea41a 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt @@ -3,6 +3,7 @@ package co.nimblehq.sample.compose.ui.screens import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.navigation.compose.rememberNavController import co.nimblehq.sample.compose.ui.AppNavigation import co.nimblehq.sample.compose.ui.theme.ComposeTheme import dagger.hilt.android.AndroidEntryPoint @@ -14,7 +15,7 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { ComposeTheme { - AppNavigation() + AppNavigation(navController = rememberNavController()) } } } diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt new file mode 100644 index 000000000..9383fb055 --- /dev/null +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainDestination.kt @@ -0,0 +1,31 @@ +package co.nimblehq.sample.compose.ui.screens.main + +import androidx.navigation.NavType +import androidx.navigation.navArgument +import co.nimblehq.sample.compose.ui.base.BaseDestination +import co.nimblehq.sample.compose.ui.models.UiModel + +const val KeyId = "id" +const val KeyModel = "model" + +sealed class MainDestination { + + object Home : BaseDestination("home") + + object Second : BaseDestination("second/{$KeyId}") { + + override val arguments = listOf( + navArgument(KeyId) { type = NavType.StringType } + ) + + fun createRoute(id: String) = apply { + destination = "second/$id" + } + } + + object Third : BaseDestination("third") { + fun addParcel(value: UiModel) = apply { + parcelableArgument = KeyModel to value + } + } +} diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainNavGraph.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainNavGraph.kt new file mode 100644 index 000000000..0ff9380f7 --- /dev/null +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/MainNavGraph.kt @@ -0,0 +1,45 @@ +package co.nimblehq.sample.compose.ui.screens.main + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.navigation +import co.nimblehq.sample.compose.ui.AppDestination +import co.nimblehq.sample.compose.ui.composable +import co.nimblehq.sample.compose.ui.models.UiModel +import co.nimblehq.sample.compose.ui.navigate +import co.nimblehq.sample.compose.ui.screens.main.home.HomeScreen +import co.nimblehq.sample.compose.ui.screens.main.second.SecondScreen +import co.nimblehq.sample.compose.ui.screens.main.third.ThirdScreen + +fun NavGraphBuilder.mainNavGraph( + navController: NavHostController, +) { + navigation( + route = AppDestination.MainNavGraph.route, + startDestination = MainDestination.Home.destination + ) { + composable(destination = MainDestination.Home) { + HomeScreen( + navigator = { destination -> + navController.navigate(destination, destination.parcelableArgument) + } + ) + } + + composable(destination = MainDestination.Second) { backStackEntry -> + SecondScreen( + navigator = { destination -> navController.navigate(destination) }, + id = backStackEntry.arguments?.getString(KeyId).orEmpty() + ) + } + + composable(destination = MainDestination.Third) { + ThirdScreen( + navigator = { destination -> navController.navigate(destination) }, + model = navController.previousBackStackEntry?.savedStateHandle?.get( + KeyModel + ) + ) + } + } +} diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreen.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreen.kt similarity index 94% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreen.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreen.kt index 3fb32e32b..fe2c70f22 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreen.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreen.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import android.Manifest.permission.* import androidx.compose.foundation.layout.* @@ -15,9 +15,9 @@ import co.nimblehq.sample.compose.R import co.nimblehq.sample.compose.extensions.collectAsEffect import co.nimblehq.sample.compose.extensions.showToast import co.nimblehq.sample.compose.lib.IsLoading -import co.nimblehq.sample.compose.ui.AppDestination +import co.nimblehq.sample.compose.ui.base.BaseDestination +import co.nimblehq.sample.compose.ui.common.AppBar import co.nimblehq.sample.compose.ui.models.UiModel -import co.nimblehq.sample.compose.ui.screens.AppBar import co.nimblehq.sample.compose.ui.showToast import co.nimblehq.sample.compose.ui.theme.ComposeTheme import com.google.accompanist.permissions.* @@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.* @Composable fun HomeScreen( viewModel: HomeViewModel = hiltViewModel(), - navigator: (destination: AppDestination) -> Unit, + navigator: (destination: BaseDestination) -> Unit, ) { val context = LocalContext.current viewModel.error.collectAsEffect { e -> e.showToast(context) } diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/HomeViewModel.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt similarity index 89% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/HomeViewModel.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt index bbbbaa0f7..593191106 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/HomeViewModel.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModel.kt @@ -1,13 +1,13 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import androidx.lifecycle.viewModelScope import co.nimblehq.sample.compose.domain.usecases.GetModelsUseCase import co.nimblehq.sample.compose.domain.usecases.IsFirstTimeLaunchPreferencesUseCase import co.nimblehq.sample.compose.domain.usecases.UpdateFirstTimeLaunchPreferencesUseCase -import co.nimblehq.sample.compose.ui.AppDestination import co.nimblehq.sample.compose.ui.base.BaseViewModel import co.nimblehq.sample.compose.ui.models.UiModel import co.nimblehq.sample.compose.ui.models.toUiModel +import co.nimblehq.sample.compose.ui.screens.main.MainDestination import co.nimblehq.sample.compose.util.DispatchersProvider import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -60,10 +60,10 @@ class HomeViewModel @Inject constructor( } fun navigateToSecond(uiModel: UiModel) { - launch { _navigator.emit(AppDestination.Second.createRoute(uiModel.id)) } + launch { _navigator.emit(MainDestination.Second.createRoute(uiModel.id)) } } fun navigateToThird(uiModel: UiModel) { - launch { _navigator.emit(AppDestination.Third.addParcel(uiModel)) } + launch { _navigator.emit(MainDestination.Third.addParcel(uiModel)) } } } diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/Item.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/Item.kt similarity index 97% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/Item.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/Item.kt index ff1698ea6..03ac9ede4 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/Item.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/Item.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import androidx.compose.foundation.* import androidx.compose.foundation.layout.* diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/ItemList.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/ItemList.kt similarity index 95% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/ItemList.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/ItemList.kt index fe08761f7..54ead9ea1 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/home/ItemList.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/home/ItemList.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/second/SecondScreen.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondScreen.kt similarity index 75% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/second/SecondScreen.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondScreen.kt index 7090fb7e8..7fc436a88 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/second/SecondScreen.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondScreen.kt @@ -1,6 +1,8 @@ -package co.nimblehq.sample.compose.ui.screens.second +package co.nimblehq.sample.compose.ui.screens.main.second -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -10,14 +12,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import co.nimblehq.sample.compose.R -import co.nimblehq.sample.compose.ui.AppDestination -import co.nimblehq.sample.compose.ui.screens.AppBar +import co.nimblehq.sample.compose.ui.base.BaseDestination +import co.nimblehq.sample.compose.ui.common.AppBar import co.nimblehq.sample.compose.ui.theme.ComposeTheme @Composable fun SecondScreen( viewModel: SecondViewModel = hiltViewModel(), - navigator: (destination: AppDestination) -> Unit, + navigator: (destination: BaseDestination) -> Unit, id: String, ) { SecondScreenContent(id) diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/second/SecondViewModel.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondViewModel.kt similarity index 78% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/second/SecondViewModel.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondViewModel.kt index df7a34fc9..3abb1ab4e 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/second/SecondViewModel.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/second/SecondViewModel.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.second +package co.nimblehq.sample.compose.ui.screens.main.second import co.nimblehq.sample.compose.ui.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/third/ThirdScreen.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt similarity index 87% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/third/ThirdScreen.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt index 7b606b2fd..05d20cfa6 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/third/ThirdScreen.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdScreen.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.third +package co.nimblehq.sample.compose.ui.screens.main.third import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -13,15 +13,15 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import co.nimblehq.sample.compose.R -import co.nimblehq.sample.compose.ui.AppDestination +import co.nimblehq.sample.compose.ui.base.BaseDestination +import co.nimblehq.sample.compose.ui.common.AppBar import co.nimblehq.sample.compose.ui.models.UiModel -import co.nimblehq.sample.compose.ui.screens.AppBar import co.nimblehq.sample.compose.ui.theme.ComposeTheme @Composable fun ThirdScreen( viewModel: ThirdViewModel = hiltViewModel(), - navigator: (destination: AppDestination) -> Unit, + navigator: (destination: BaseDestination) -> Unit, model: UiModel?, ) { ThirdScreenContent(data = model) diff --git a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/third/ThirdViewModel.kt b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdViewModel.kt similarity index 78% rename from sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/third/ThirdViewModel.kt rename to sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdViewModel.kt index 6638d6fe0..60aea8133 100644 --- a/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/third/ThirdViewModel.kt +++ b/sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/main/third/ThirdViewModel.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.third +package co.nimblehq.sample.compose.ui.screens.main.third import co.nimblehq.sample.compose.ui.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel diff --git a/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreenTest.kt b/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt similarity index 91% rename from sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreenTest.kt rename to sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt index 43058f8e3..4ca17b626 100644 --- a/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/home/HomeScreenTest.kt +++ b/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import androidx.activity.compose.setContent import androidx.compose.ui.test.* @@ -9,9 +9,10 @@ import androidx.test.rule.GrantPermissionRule import co.nimblehq.sample.compose.R import co.nimblehq.sample.compose.domain.usecases.* import co.nimblehq.sample.compose.test.MockUtil -import co.nimblehq.sample.compose.ui.AppDestination +import co.nimblehq.sample.compose.ui.base.BaseDestination import co.nimblehq.sample.compose.ui.screens.BaseScreenTest import co.nimblehq.sample.compose.ui.screens.MainActivity +import co.nimblehq.sample.compose.ui.screens.main.MainDestination import co.nimblehq.sample.compose.ui.theme.ComposeTheme import io.kotest.matchers.shouldBe import io.mockk.* @@ -45,7 +46,7 @@ class HomeScreenTest : BaseScreenTest() { mockk() private lateinit var viewModel: HomeViewModel - private var expectedAppDestination: AppDestination? = null + private var expectedDestination: BaseDestination? = null @Before fun setUp() { @@ -105,7 +106,7 @@ class HomeScreenTest : BaseScreenTest() { fun `When clicking on a list item, it navigates to Second screen`() = initComposable { onNodeWithText("1").performClick() - assertEquals(expectedAppDestination, AppDestination.Second) + assertEquals(expectedDestination, MainDestination.Second) } private fun initComposable( @@ -117,7 +118,7 @@ class HomeScreenTest : BaseScreenTest() { ComposeTheme { HomeScreen( viewModel = viewModel, - navigator = { destination -> expectedAppDestination = destination }, + navigator = { destination -> expectedDestination = destination }, ) } } diff --git a/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/home/HomeViewModelTest.kt b/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModelTest.kt similarity index 96% rename from sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/home/HomeViewModelTest.kt rename to sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModelTest.kt index 2085d0f16..1d8de6c1d 100644 --- a/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/home/HomeViewModelTest.kt +++ b/sample-compose/app/src/test/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeViewModelTest.kt @@ -1,4 +1,4 @@ -package co.nimblehq.sample.compose.ui.screens.home +package co.nimblehq.sample.compose.ui.screens.main.home import app.cash.turbine.test import co.nimblehq.sample.compose.domain.usecases.GetModelsUseCase @@ -6,7 +6,7 @@ import co.nimblehq.sample.compose.domain.usecases.IsFirstTimeLaunchPreferencesUs import co.nimblehq.sample.compose.domain.usecases.UpdateFirstTimeLaunchPreferencesUseCase import co.nimblehq.sample.compose.test.CoroutineTestRule import co.nimblehq.sample.compose.test.MockUtil -import co.nimblehq.sample.compose.ui.AppDestination +import co.nimblehq.sample.compose.ui.screens.main.MainDestination import co.nimblehq.sample.compose.ui.models.toUiModel import co.nimblehq.sample.compose.util.DispatchersProvider import io.kotest.matchers.shouldBe @@ -86,7 +86,7 @@ class HomeViewModelTest { viewModel.navigator.test { viewModel.navigateToSecond(MockUtil.models[0].toUiModel()) - expectMostRecentItem() shouldBe AppDestination.Second + expectMostRecentItem() shouldBe MainDestination.Second } } diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppDestination.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppDestination.kt index b5526eadd..be93bcfd7 100644 --- a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppDestination.kt +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppDestination.kt @@ -1,14 +1,10 @@ package co.nimblehq.template.compose.ui -import androidx.navigation.* +import co.nimblehq.template.compose.ui.base.BaseDestination -sealed class AppDestination(val route: String = "") { +sealed class AppDestination { - open val arguments: List = emptyList() + object RootNavGraph : BaseDestination("rootNavGraph") - open var destination: String = route - - object Up : AppDestination() - - object Home : AppDestination("home") + object MainNavGraph : BaseDestination("mainNavGraph") } diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppNavGraph.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppNavGraph.kt new file mode 100644 index 000000000..f2b975f97 --- /dev/null +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppNavGraph.kt @@ -0,0 +1,44 @@ +package co.nimblehq.template.compose.ui + +import androidx.compose.runtime.Composable +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavDeepLink +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import co.nimblehq.template.compose.ui.base.BaseDestination +import co.nimblehq.template.compose.ui.screens.main.mainNavGraph + +@Composable +fun AppNavigation( + navController: NavHostController, +) { + NavHost( + navController = navController, + route = AppDestination.RootNavGraph.route, + startDestination = AppDestination.MainNavGraph.destination + ) { + mainNavGraph(navController = navController) + } +} + +fun NavGraphBuilder.composable( + destination: BaseDestination, + deepLinks: List = emptyList(), + content: @Composable (NavBackStackEntry) -> Unit, +) { + composable( + route = destination.route, + arguments = destination.arguments, + deepLinks = deepLinks, + content = content + ) +} + +fun NavHostController.navigate(destination: BaseDestination) { + when (destination) { + is BaseDestination.Up -> navigateUp() + else -> navigate(route = destination.destination) + } +} diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppNavigation.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppNavigation.kt deleted file mode 100644 index 7ed4806f0..000000000 --- a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/AppNavigation.kt +++ /dev/null @@ -1,43 +0,0 @@ -package co.nimblehq.template.compose.ui - -import androidx.compose.runtime.Composable -import androidx.navigation.* -import androidx.navigation.compose.* -import co.nimblehq.template.compose.ui.screens.home.HomeScreen - -@Composable -fun AppNavigation( - navController: NavHostController = rememberNavController(), - startDestination: String = AppDestination.Home.destination -) { - NavHost( - navController = navController, - startDestination = startDestination - ) { - composable(AppDestination.Home) { - HomeScreen( - navigator = { destination -> navController.navigate(destination) } - ) - } - } -} - -private fun NavGraphBuilder.composable( - destination: AppDestination, - deepLinks: List = emptyList(), - content: @Composable (NavBackStackEntry) -> Unit -) { - composable( - route = destination.route, - arguments = destination.arguments, - deepLinks = deepLinks, - content = content - ) -} - -private fun NavHostController.navigate(appDestination: AppDestination) { - when (appDestination) { - is AppDestination.Up -> navigateUp() - else -> navigate(route = appDestination.destination) - } -} diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseDestination.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseDestination.kt new file mode 100644 index 000000000..3247e7561 --- /dev/null +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseDestination.kt @@ -0,0 +1,12 @@ +package co.nimblehq.template.compose.ui.base + +import androidx.navigation.NamedNavArgument + +abstract class BaseDestination(val route: String = "") { + + open val arguments: List = emptyList() + + open var destination: String = route + + object Up : BaseDestination() +} diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseViewModel.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseViewModel.kt index b6f4f4068..44b27a425 100644 --- a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseViewModel.kt +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/base/BaseViewModel.kt @@ -2,7 +2,6 @@ package co.nimblehq.template.compose.ui.base import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import co.nimblehq.template.compose.ui.AppDestination import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlin.coroutines.CoroutineContext @@ -19,7 +18,7 @@ abstract class BaseViewModel : ViewModel() { protected val _error = MutableSharedFlow() val error = _error.asSharedFlow() - protected val _navigator = MutableSharedFlow() + protected val _navigator = MutableSharedFlow() val navigator = _navigator.asSharedFlow() /** diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/MainActivity.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/MainActivity.kt index ee3b2cca7..87759c1be 100644 --- a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/MainActivity.kt +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/MainActivity.kt @@ -3,6 +3,7 @@ package co.nimblehq.template.compose.ui.screens import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.navigation.compose.rememberNavController import co.nimblehq.template.compose.ui.AppNavigation import co.nimblehq.template.compose.ui.theme.ComposeTheme import dagger.hilt.android.AndroidEntryPoint @@ -14,7 +15,7 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { ComposeTheme { - AppNavigation() + AppNavigation(navController = rememberNavController()) } } } diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/MainDestination.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/MainDestination.kt new file mode 100644 index 000000000..038759363 --- /dev/null +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/MainDestination.kt @@ -0,0 +1,8 @@ +package co.nimblehq.template.compose.ui.screens.main + +import co.nimblehq.template.compose.ui.base.BaseDestination + +sealed class MainDestination { + + object Home : BaseDestination("home") +} diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/MainNavGraph.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/MainNavGraph.kt new file mode 100644 index 000000000..b6230c0dd --- /dev/null +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/MainNavGraph.kt @@ -0,0 +1,24 @@ +package co.nimblehq.template.compose.ui.screens.main + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.navigation +import co.nimblehq.template.compose.ui.AppDestination +import co.nimblehq.template.compose.ui.composable +import co.nimblehq.template.compose.ui.navigate +import co.nimblehq.template.compose.ui.screens.main.home.HomeScreen + +fun NavGraphBuilder.mainNavGraph( + navController: NavHostController, +) { + navigation( + route = AppDestination.MainNavGraph.route, + startDestination = MainDestination.Home.destination + ) { + composable(MainDestination.Home) { + HomeScreen( + navigator = { destination -> navController.navigate(destination) } + ) + } + } +} diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/home/HomeScreen.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/home/HomeScreen.kt similarity index 82% rename from template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/home/HomeScreen.kt rename to template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/home/HomeScreen.kt index 835517537..dda7bd4d4 100644 --- a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/home/HomeScreen.kt +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/home/HomeScreen.kt @@ -1,6 +1,10 @@ -package co.nimblehq.template.compose.ui.screens.home +package co.nimblehq.template.compose.ui.screens.main.home -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -13,7 +17,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import co.nimblehq.template.compose.R import co.nimblehq.template.compose.extensions.collectAsEffect -import co.nimblehq.template.compose.ui.AppDestination +import co.nimblehq.template.compose.ui.base.BaseDestination import co.nimblehq.template.compose.ui.models.UiModel import co.nimblehq.template.compose.ui.showToast import co.nimblehq.template.compose.ui.theme.AppTheme.dimensions @@ -23,7 +27,7 @@ import timber.log.Timber @Composable fun HomeScreen( viewModel: HomeViewModel = hiltViewModel(), - navigator: (destination: AppDestination) -> Unit + navigator: (destination: BaseDestination) -> Unit, ) { val context = LocalContext.current viewModel.error.collectAsEffect { e -> e.showToast(context) } diff --git a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/home/HomeViewModel.kt b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/home/HomeViewModel.kt similarity index 94% rename from template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/home/HomeViewModel.kt rename to template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/home/HomeViewModel.kt index c906eb929..0f2c7a82b 100644 --- a/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/home/HomeViewModel.kt +++ b/template-compose/app/src/main/java/co/nimblehq/template/compose/ui/screens/main/home/HomeViewModel.kt @@ -1,4 +1,4 @@ -package co.nimblehq.template.compose.ui.screens.home +package co.nimblehq.template.compose.ui.screens.main.home import androidx.lifecycle.viewModelScope import co.nimblehq.template.compose.domain.usecases.UseCase diff --git a/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/home/HomeScreenTest.kt b/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/main/home/HomeScreenTest.kt similarity index 90% rename from template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/home/HomeScreenTest.kt rename to template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/main/home/HomeScreenTest.kt index b61dd0c11..e3a2d12d2 100644 --- a/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/home/HomeScreenTest.kt +++ b/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/main/home/HomeScreenTest.kt @@ -1,4 +1,4 @@ -package co.nimblehq.template.compose.ui.screens.home +package co.nimblehq.template.compose.ui.screens.main.home import androidx.activity.compose.setContent import androidx.compose.ui.test.* @@ -7,7 +7,7 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule import co.nimblehq.template.compose.R import co.nimblehq.template.compose.domain.usecases.UseCase import co.nimblehq.template.compose.test.MockUtil -import co.nimblehq.template.compose.ui.AppDestination +import co.nimblehq.template.compose.ui.base.BaseDestination import co.nimblehq.template.compose.ui.screens.BaseScreenTest import co.nimblehq.template.compose.ui.screens.MainActivity import co.nimblehq.template.compose.ui.theme.ComposeTheme @@ -31,7 +31,7 @@ class HomeScreenTest : BaseScreenTest() { private val mockUseCase: UseCase = mockk() private lateinit var viewModel: HomeViewModel - private var expectedAppDestination: AppDestination? = null + private var expectedDestination: BaseDestination? = null @Before fun setUp() { @@ -67,7 +67,7 @@ class HomeScreenTest : BaseScreenTest() { ComposeTheme { HomeScreen( viewModel = viewModel, - navigator = { destination -> expectedAppDestination = destination } + navigator = { destination -> expectedDestination = destination } ) } } diff --git a/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/home/HomeViewModelTest.kt b/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/main/home/HomeViewModelTest.kt similarity index 97% rename from template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/home/HomeViewModelTest.kt rename to template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/main/home/HomeViewModelTest.kt index 2ac3e76fd..d520c6bea 100644 --- a/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/home/HomeViewModelTest.kt +++ b/template-compose/app/src/test/java/co/nimblehq/template/compose/ui/screens/main/home/HomeViewModelTest.kt @@ -1,4 +1,4 @@ -package co.nimblehq.template.compose.ui.screens.home +package co.nimblehq.template.compose.ui.screens.main.home import app.cash.turbine.test import co.nimblehq.template.compose.domain.usecases.UseCase