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

Main 화면 네비게이션 구조 feature 모듈을 의존하는 형태로 개선 #56

Merged
merged 4 commits into from
Jul 19, 2023
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

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.droidknights.app2023.feature.home.navigation

import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.droidknights.app2023.feature.home.HomeScreen

fun NavController.navigateHome() {
navigate(HomeRoute.route)
}

fun NavGraphBuilder.homeNavGraph() {
composable(route = HomeRoute.route) {
HomeScreen()
}
}

object HomeRoute {
const val route = "home"
}
Comment on lines +18 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순 상수값으로도 충분하다고 생각했는데 HomeRoute가 object여야할 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wisemuji
Route를 만들어주는 역할을 하는 목적으로 보면 object로 관리하는 이점이 있습니다.
ref : https://github.com/DroidKaigi/conference-app-2022/blob/main/feature/sessions/src/main/java/io/github/droidkaigi/confsched2022/feature/sessions/SessionsNavGraph.kt

This file was deleted.

This file was deleted.

2 changes: 2 additions & 0 deletions feature/main/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ android {
}

dependencies {
implementation(project(":feature:home"))

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.runtimeCompose)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,47 @@
package com.droidknights.app2023.feature.main

import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.performClick
import androidx.navigation.compose.ComposeNavigator
import androidx.navigation.testing.TestNavHostController
import com.droidknights.app2023.core.navigation.HomeNavigation
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class MainScreenTest {

@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
private lateinit var navController: TestNavHostController

@Before
fun setup() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current)
navController.navigatorProvider.addNavigator(ComposeNavigator())
MainScreen(MainNavigator(navController, FakeHomeNavigation()))
MainScreen(rememberMainNavigator(navController = navController))
}
}

@Test
fun 시작_화면은_홈이다() {
val actual = navController.currentBackStackEntry?.destination?.route
assertEquals("home", actual)
}

@Test
fun 설정_탭을_클릭하면_설정으로_이동한다() {
// when
composeTestRule
.onNodeWithContentDescription("설정")
.performClick()

// then
val actual = navController.currentBackStackEntry?.destination?.route
assertEquals("setting", actual)
}
}

private class FakeHomeNavigation : HomeNavigation {
@Composable
override fun Content() {
// no-op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,19 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.core.view.WindowCompat
import com.droidknights.app2023.core.designsystem.theme.KnightsTheme
import com.droidknights.app2023.core.navigation.HomeNavigation
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : ComponentActivity() {

@Inject
lateinit var homeNavigation: HomeNavigation


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
KnightsTheme {
MainScreen(homeNavigation)
MainScreen()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,83 +1,43 @@
package com.droidknights.app2023.feature.main

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.droidknights.app2023.core.navigation.HomeNavigation
import com.droidknights.app2023.core.navigation.MainDestination
import com.droidknights.app2023.feature.home.navigation.HomeRoute
import com.droidknights.app2023.feature.home.navigation.navigateHome

internal class MainNavigator(
private val navController: NavHostController,
private val homeNavigation: HomeNavigation,
startTab: MainTab = MainTab.HOME,
val navController: NavHostController,
) {
private val startDestination: MainDestination = MainDestination.Home
private var currentDestination: MainDestination by mutableStateOf(startDestination)

val currentTab: MainTab
get() = when (currentDestination) {
MainDestination.Home -> MainTab.HOME
MainDestination.Setting -> MainTab.SETTING
MainDestination.Temp -> MainTab.TEMP
}

@Composable
fun Content() {
NavHost(
navController = navController,
startDestination = startDestination.route,
) {
composable(MainDestination.Home.route) {
with(homeNavigation) {
Content()
}
}

// TODO: 각 모듈로 이동
val content: @Composable (String) -> Unit = {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
content = { Text(text = it) }
)
}
composable("setting") { content("setting") }
composable("temp") { content("temp") }
}
val startDestination: String = when (startTab) {
MainTab.HOME -> HomeRoute.route
MainTab.SETTING -> "setting"
MainTab.TEMP -> "temp"
}

var currentTab: MainTab by mutableStateOf(startTab)
private set

fun navigate(tab: MainTab) {
val destination = when (tab) {
MainTab.SETTING -> MainDestination.Setting
MainTab.HOME -> MainDestination.Home
MainTab.TEMP -> MainDestination.Temp
}
navigate(destination)
}

private fun navigate(destination: MainDestination) {
if (destination == currentDestination) {
return
if (tab == currentTab) return
when (tab) {
MainTab.SETTING -> navController.navigate("setting") // TODO: navigate settings
MainTab.HOME -> navController.navigateHome()
MainTab.TEMP -> navController.navigate("temp") // TODO: ???
}
currentDestination = destination
navController.navigate(destination.route)
currentTab = tab
}
}

@Composable
internal fun rememberMainNavigator(
homeNavigation: HomeNavigation,
starTab: MainTab = MainTab.HOME,
navController: NavHostController = rememberNavController(),
): MainNavigator = remember(navController, homeNavigation) {
MainNavigator(navController, homeNavigation)
): MainNavigator = remember(navController) {
MainNavigator(starTab, navController)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,20 @@ import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.droidknights.app2023.core.navigation.HomeNavigation
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.droidknights.app2023.feature.home.navigation.homeNavGraph

@Composable
internal fun MainScreen(
homeNavigation: HomeNavigation,
) {
val navigator = rememberMainNavigator(homeNavigation)
MainScreen(navigator)
}

@Composable
internal fun MainScreen(navigator: MainNavigator) {
internal fun MainScreen(navigator: MainNavigator = rememberMainNavigator()) {
Scaffold(
content = { padding ->
Box(
Expand All @@ -45,8 +40,22 @@ internal fun MainScreen(navigator: MainNavigator) {
.background(Color(0xFFF9F9F9))
.padding(padding)
) {
with(navigator) {
Content()
NavHost(
navController = navigator.navController,
startDestination = navigator.startDestination,
) {
homeNavGraph()

// TODO: 각 모듈로 이동
val content: @Composable (String) -> Unit = {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
content = { Text(text = it) }
)
}
composable("setting") { content("setting") }
composable("temp") { content("temp") }
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ kotest = "5.6.2"
# https://github.com/detekt/detekt
detekt = "1.23.0"

coroutine = "1.7.0"
coroutine = "1.7.2"

[libraries]
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
Expand Down