Skip to content

Commit c836a38

Browse files
authored
Merge pull request #47 from YAPP-Github/feature/#46-navigation
[Feature/#46] 화면 연결 네비게이션 구현
2 parents f326a03 + f12ae26 commit c836a38

File tree

32 files changed

+677
-21
lines changed

32 files changed

+677
-21
lines changed

app/src/main/java/com/threegap/bitnagil/MainNavHost.kt

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ import androidx.compose.ui.Modifier
55
import androidx.navigation.compose.NavHost
66
import androidx.navigation.compose.composable
77
import androidx.navigation.toRoute
8-
import com.threegap.bitnagil.presentation.home.HomeScreenContainer
8+
import com.threegap.bitnagil.navigation.home.HomeNavHost
9+
import com.threegap.bitnagil.presentation.emotion.EmotionScreenContainer
910
import com.threegap.bitnagil.presentation.intro.IntroScreenContainer
1011
import com.threegap.bitnagil.presentation.login.LoginScreenContainer
12+
import com.threegap.bitnagil.presentation.onboarding.OnBoardingScreenContainer
13+
import com.threegap.bitnagil.presentation.setting.SettingScreenContainer
1114
import com.threegap.bitnagil.presentation.splash.SplashScreenContainer
1215
import com.threegap.bitnagil.presentation.terms.TermsAgreementScreenContainer
1316
import com.threegap.bitnagil.presentation.webview.BitnagilWebViewScreen
17+
import com.threegap.bitnagil.presentation.writeroutine.WriteRoutineScreenContainer
1418

1519
@Composable
1620
fun MainNavHost(
@@ -25,7 +29,13 @@ fun MainNavHost(
2529
composable<Route.Splash> {
2630
SplashScreenContainer(
2731
navigateToIntro = { navigator.navController.navigate(Route.Intro) },
28-
navigateToHome = { navigator.navController.navigate(Route.Home) },
32+
navigateToHome = {
33+
navigator.navController.navigate(Route.Home) {
34+
popUpTo(navigator.navController.graph.startDestinationId) {
35+
inclusive = true
36+
}
37+
}
38+
},
2939
)
3040
}
3141

@@ -37,7 +47,13 @@ fun MainNavHost(
3747

3848
composable<Route.Login> {
3949
LoginScreenContainer(
40-
navigateToHome = { navigator.navController.navigate(Route.Home) },
50+
navigateToHome = {
51+
navigator.navController.navigate(Route.Home) {
52+
popUpTo(navigator.navController.graph.startDestinationId) {
53+
inclusive = true
54+
}
55+
}
56+
},
4157
navigateToTermsAgreement = { navigator.navController.navigate(Route.TermsAgreement) },
4258
)
4359
}
@@ -60,13 +76,35 @@ fun MainNavHost(
6076
),
6177
)
6278
},
63-
navigateToOnBoarding = { },
79+
navigateToOnBoarding = {
80+
navigator.navController.navigate(Route.OnBoarding)
81+
},
6482
navigateToBack = { navigator.navController.popBackStack() },
6583
)
6684
}
6785

6886
composable<Route.Home> {
69-
HomeScreenContainer()
87+
HomeNavHost(
88+
navigateToSetting = {
89+
navigator.navController.navigate(Route.Setting)
90+
},
91+
navigateToOnBoarding = {
92+
navigator.navController.navigate(Route.OnBoarding)
93+
},
94+
navigateToNotice = {
95+
},
96+
navigateToQnA = {
97+
},
98+
navigateToRegisterRoutine = { routineId ->
99+
navigator.navController.navigate(Route.WriteRoutine(routineId = routineId))
100+
},
101+
navigateToEditRoutine = { routineId ->
102+
navigator.navController.navigate(Route.WriteRoutine(routineId = routineId, isRegister = false))
103+
},
104+
navigateToEmotion = {
105+
navigator.navController.navigate(Route.Emotion)
106+
},
107+
)
70108
}
71109

72110
composable<Route.WebView> {
@@ -77,5 +115,67 @@ fun MainNavHost(
77115
onBackClick = { navigator.navController.popBackStack() },
78116
)
79117
}
118+
119+
composable<Route.Setting> {
120+
SettingScreenContainer(
121+
navigateToBack = {
122+
navigator.navController.popBackStack()
123+
},
124+
navigateToTermsOfService = {
125+
navigator.navController.navigate(
126+
Route.WebView(
127+
title = "약관 동의",
128+
url = "https://complex-wombat-99f.notion.site/2025-7-20-236f4587491d8071833adfaf8115bce2",
129+
),
130+
)
131+
},
132+
navigateToPrivacyPolicy = {
133+
navigator.navController.navigate(
134+
Route.WebView(
135+
title = "약관 동의",
136+
url = "https://complex-wombat-99f.notion.site/2025-07-20-236f4587491d80308016eb810692d18b",
137+
),
138+
)
139+
},
140+
navigateToIntro = {
141+
navigator.navController.navigate(Route.Intro) {
142+
popUpTo(0) {
143+
inclusive = true
144+
}
145+
}
146+
},
147+
)
148+
}
149+
150+
composable<Route.OnBoarding> {
151+
OnBoardingScreenContainer(
152+
navigateToHome = {
153+
navigator.navController.navigate(Route.Home) {
154+
popUpTo(navigator.navController.graph.startDestinationId) {
155+
inclusive = true
156+
}
157+
}
158+
},
159+
navigateToBack = {
160+
navigator.navController.popBackStack()
161+
},
162+
)
163+
}
164+
165+
composable<Route.WriteRoutine> {
166+
WriteRoutineScreenContainer(
167+
navigateToBack = {
168+
navigator.navController.popBackStack()
169+
},
170+
)
171+
}
172+
173+
composable<Route.Emotion> {
174+
EmotionScreenContainer(
175+
navigateToBack = {
176+
navigator.navController.popBackStack()
177+
},
178+
)
179+
}
80180
}
81181
}

app/src/main/java/com/threegap/bitnagil/Route.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,19 @@ sealed interface Route {
2424
val title: String,
2525
val url: String,
2626
) : Route
27+
28+
@Serializable
29+
data object Setting : Route
30+
31+
@Serializable
32+
data object OnBoarding : Route
33+
34+
@Serializable
35+
data class WriteRoutine(
36+
val routineId: String? = null,
37+
val isRegister: Boolean = true,
38+
) : Route
39+
40+
@Serializable
41+
data object Emotion : Route
2742
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package com.threegap.bitnagil.navigation.home
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.clickable
6+
import androidx.compose.foundation.interaction.MutableInteractionSource
7+
import androidx.compose.foundation.interaction.collectIsPressedAsState
8+
import androidx.compose.foundation.layout.Arrangement
9+
import androidx.compose.foundation.layout.Column
10+
import androidx.compose.foundation.layout.Row
11+
import androidx.compose.foundation.layout.fillMaxWidth
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
14+
import androidx.compose.material3.Text
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.runtime.getValue
17+
import androidx.compose.runtime.remember
18+
import androidx.compose.ui.Alignment
19+
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.graphics.ColorFilter
21+
import androidx.compose.ui.res.painterResource
22+
import androidx.compose.ui.tooling.preview.Preview
23+
import androidx.compose.ui.unit.dp
24+
import androidx.navigation.NavController
25+
import androidx.navigation.compose.currentBackStackEntryAsState
26+
import com.threegap.bitnagil.designsystem.BitnagilTheme
27+
28+
@Composable
29+
fun HomeBottomNavigationBar(
30+
navController: NavController,
31+
) {
32+
val navBackStackEntry by navController.currentBackStackEntryAsState()
33+
34+
Row(
35+
modifier = Modifier
36+
.fillMaxWidth()
37+
.background(color = BitnagilTheme.colors.white)
38+
.padding(horizontal = 16.dp, vertical = 7.dp),
39+
horizontalArrangement = Arrangement.spacedBy(12.dp),
40+
) {
41+
HomeRoute.entries.map { homeRoute ->
42+
HomeBottomNavigationItem(
43+
modifier = Modifier.weight(1f),
44+
selectIconResourceId = homeRoute.selectIconResourceId,
45+
unSelectIconResourceId = homeRoute.unSelectIconResourceId,
46+
title = homeRoute.title,
47+
onClick = {
48+
navController.navigate(homeRoute.route) {
49+
popUpTo(0) { inclusive = true }
50+
}
51+
},
52+
selected = navBackStackEntry?.destination?.route == homeRoute.route,
53+
)
54+
}
55+
}
56+
}
57+
58+
@Composable
59+
private fun HomeBottomNavigationItem(
60+
modifier: Modifier = Modifier,
61+
selectIconResourceId: Int,
62+
unSelectIconResourceId: Int,
63+
title: String,
64+
onClick: () -> Unit,
65+
selected: Boolean,
66+
) {
67+
val interactionSource = remember { MutableInteractionSource() }
68+
val isPressed by interactionSource.collectIsPressedAsState()
69+
70+
val contentTintColor = when {
71+
isPressed -> BitnagilTheme.colors.navy300
72+
selected -> BitnagilTheme.colors.navy500
73+
else -> BitnagilTheme.colors.navy100
74+
}
75+
val iconResourceId = if (selected) selectIconResourceId else unSelectIconResourceId
76+
77+
Column(
78+
modifier = modifier.clickable(
79+
onClick = onClick,
80+
interactionSource = interactionSource,
81+
indication = null,
82+
),
83+
horizontalAlignment = Alignment.CenterHorizontally,
84+
) {
85+
Image(
86+
painter = painterResource(id = iconResourceId),
87+
contentDescription = title,
88+
modifier = Modifier.padding(4.dp).size(24.dp),
89+
colorFilter = ColorFilter.tint(color = contentTintColor),
90+
)
91+
92+
Text(
93+
text = title,
94+
style = BitnagilTheme.typography.caption2Medium,
95+
color = contentTintColor,
96+
)
97+
}
98+
}
99+
100+
@Composable
101+
@Preview
102+
private fun HomeBottomNavigationBarPreview() {
103+
val navigator = rememberHomeNavigator()
104+
105+
HomeBottomNavigationBar(
106+
navController = navigator.navController,
107+
108+
)
109+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.threegap.bitnagil.navigation.home
2+
3+
import android.annotation.SuppressLint
4+
import android.app.Activity
5+
import androidx.activity.compose.BackHandler
6+
import androidx.compose.foundation.layout.fillMaxSize
7+
import androidx.compose.material3.Scaffold
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.getValue
10+
import androidx.compose.runtime.mutableLongStateOf
11+
import androidx.compose.runtime.remember
12+
import androidx.compose.runtime.setValue
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.platform.LocalContext
15+
import androidx.navigation.compose.NavHost
16+
import androidx.navigation.compose.composable
17+
import com.threegap.bitnagil.presentation.home.HomeScreenContainer
18+
import com.threegap.bitnagil.presentation.mypage.MyPageScreenContainer
19+
import com.threegap.bitnagil.presentation.recommendroutine.RecommendRoutineScreenContainer
20+
21+
@Composable
22+
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
23+
fun HomeNavHost(
24+
modifier: Modifier = Modifier,
25+
navigateToSetting: () -> Unit,
26+
navigateToOnBoarding: () -> Unit,
27+
navigateToNotice: () -> Unit,
28+
navigateToQnA: () -> Unit,
29+
navigateToRegisterRoutine: (String?) -> Unit,
30+
navigateToEditRoutine: (String) -> Unit,
31+
navigateToEmotion: () -> Unit,
32+
) {
33+
val navigator = rememberHomeNavigator()
34+
35+
DoubleBackButtonPressedHandler()
36+
37+
Scaffold(
38+
modifier = Modifier.fillMaxSize(),
39+
bottomBar = {
40+
HomeBottomNavigationBar(navController = navigator.navController)
41+
},
42+
content = { _ ->
43+
NavHost(
44+
navController = navigator.navController,
45+
startDestination = navigator.startDestination,
46+
modifier = modifier,
47+
) {
48+
composable(HomeRoute.Home.route) {
49+
HomeScreenContainer(
50+
navigateToRegisterRoutine = {
51+
navigateToRegisterRoutine(null)
52+
},
53+
navigateToEditRoutine = navigateToEditRoutine,
54+
navigateToEmotion = navigateToEmotion,
55+
)
56+
}
57+
58+
composable(HomeRoute.RecommendRoutine.route) {
59+
RecommendRoutineScreenContainer(
60+
navigateToEmotion = navigateToEmotion,
61+
navigateToRegisterRoutine = navigateToRegisterRoutine,
62+
)
63+
}
64+
65+
composable(HomeRoute.MyPage.route) {
66+
MyPageScreenContainer(
67+
navigateToSetting = navigateToSetting,
68+
navigateToOnBoarding = navigateToOnBoarding,
69+
navigateToNotice = navigateToNotice,
70+
navigateToQnA = navigateToQnA,
71+
)
72+
}
73+
}
74+
},
75+
)
76+
}
77+
78+
@Composable
79+
fun DoubleBackButtonPressedHandler() {
80+
val context = LocalContext.current
81+
var backPressedTimeMillis by remember { mutableLongStateOf(0L) }
82+
BackHandler {
83+
if (System.currentTimeMillis() - backPressedTimeMillis < 2000) {
84+
backPressedTimeMillis = 0
85+
(context as? Activity)?.finish()
86+
} else {
87+
backPressedTimeMillis = System.currentTimeMillis()
88+
}
89+
}
90+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.threegap.bitnagil.navigation.home
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.remember
5+
import androidx.navigation.NavHostController
6+
import androidx.navigation.compose.rememberNavController
7+
8+
class HomeNavigator(
9+
val navController: NavHostController,
10+
) {
11+
val startDestination = HomeRoute.Home.route
12+
}
13+
14+
@Composable
15+
fun rememberHomeNavigator(navController: NavHostController = rememberNavController()): HomeNavigator =
16+
remember(navController) {
17+
HomeNavigator(navController)
18+
}

0 commit comments

Comments
 (0)