Skip to content
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
110 changes: 105 additions & 5 deletions app/src/main/java/com/threegap/bitnagil/MainNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
import com.threegap.bitnagil.presentation.home.HomeScreenContainer
import com.threegap.bitnagil.navigation.home.HomeNavHost
import com.threegap.bitnagil.presentation.emotion.EmotionScreenContainer
import com.threegap.bitnagil.presentation.intro.IntroScreenContainer
import com.threegap.bitnagil.presentation.login.LoginScreenContainer
import com.threegap.bitnagil.presentation.onboarding.OnBoardingScreenContainer
import com.threegap.bitnagil.presentation.setting.SettingScreenContainer
import com.threegap.bitnagil.presentation.splash.SplashScreenContainer
import com.threegap.bitnagil.presentation.terms.TermsAgreementScreenContainer
import com.threegap.bitnagil.presentation.webview.BitnagilWebViewScreen
import com.threegap.bitnagil.presentation.writeroutine.WriteRoutineScreenContainer

@Composable
fun MainNavHost(
Expand All @@ -25,7 +29,13 @@ fun MainNavHost(
composable<Route.Splash> {
SplashScreenContainer(
navigateToIntro = { navigator.navController.navigate(Route.Intro) },
navigateToHome = { navigator.navController.navigate(Route.Home) },
navigateToHome = {
navigator.navController.navigate(Route.Home) {
popUpTo(navigator.navController.graph.startDestinationId) {
inclusive = true
}
}
},
)
}

Expand All @@ -37,7 +47,13 @@ fun MainNavHost(

composable<Route.Login> {
LoginScreenContainer(
navigateToHome = { navigator.navController.navigate(Route.Home) },
navigateToHome = {
navigator.navController.navigate(Route.Home) {
popUpTo(navigator.navController.graph.startDestinationId) {
inclusive = true
}
}
},
navigateToTermsAgreement = { navigator.navController.navigate(Route.TermsAgreement) },
)
}
Expand All @@ -60,13 +76,35 @@ fun MainNavHost(
),
)
},
navigateToOnBoarding = { },
navigateToOnBoarding = {
navigator.navController.navigate(Route.OnBoarding)
},
navigateToBack = { navigator.navController.popBackStack() },
)
}

composable<Route.Home> {
HomeScreenContainer()
HomeNavHost(
navigateToSetting = {
navigator.navController.navigate(Route.Setting)
},
navigateToOnBoarding = {
navigator.navController.navigate(Route.OnBoarding)
},
navigateToNotice = {
},
navigateToQnA = {
},
navigateToRegisterRoutine = { routineId ->
navigator.navController.navigate(Route.WriteRoutine(routineId = routineId))
},
navigateToEditRoutine = { routineId ->
navigator.navController.navigate(Route.WriteRoutine(routineId = routineId, isRegister = false))
},
navigateToEmotion = {
navigator.navController.navigate(Route.Emotion)
},
)
}

composable<Route.WebView> {
Expand All @@ -77,5 +115,67 @@ fun MainNavHost(
onBackClick = { navigator.navController.popBackStack() },
)
}

composable<Route.Setting> {
SettingScreenContainer(
navigateToBack = {
navigator.navController.popBackStack()
},
navigateToTermsOfService = {
navigator.navController.navigate(
Route.WebView(
title = "약관 동의",
url = "https://complex-wombat-99f.notion.site/2025-7-20-236f4587491d8071833adfaf8115bce2",
),
)
},
navigateToPrivacyPolicy = {
navigator.navController.navigate(
Route.WebView(
title = "약관 동의",
url = "https://complex-wombat-99f.notion.site/2025-07-20-236f4587491d80308016eb810692d18b",
),
)
},
navigateToIntro = {
navigator.navController.navigate(Route.Intro) {
popUpTo(0) {
inclusive = true
}
}
},
)
}

composable<Route.OnBoarding> {
OnBoardingScreenContainer(
navigateToHome = {
navigator.navController.navigate(Route.Home) {
popUpTo(navigator.navController.graph.startDestinationId) {
inclusive = true
}
}
},
navigateToBack = {
navigator.navController.popBackStack()
},
)
}

composable<Route.WriteRoutine> {
WriteRoutineScreenContainer(
navigateToBack = {
navigator.navController.popBackStack()
},
)
}

composable<Route.Emotion> {
EmotionScreenContainer(
navigateToBack = {
navigator.navController.popBackStack()
},
)
}
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/threegap/bitnagil/Route.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,19 @@ sealed interface Route {
val title: String,
val url: String,
) : Route

@Serializable
data object Setting : Route

@Serializable
data object OnBoarding : Route

@Serializable
data class WriteRoutine(
val routineId: String? = null,
val isRegister: Boolean = true,
) : Route

@Serializable
data object Emotion : Route
}
Comment thread
wjdrjs00 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.threegap.bitnagil.navigation.home

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import com.threegap.bitnagil.designsystem.BitnagilTheme

@Composable
fun HomeBottomNavigationBar(
navController: NavController,
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()

Row(
modifier = Modifier
.fillMaxWidth()
.background(color = BitnagilTheme.colors.white)
.padding(horizontal = 16.dp, vertical = 7.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
HomeRoute.entries.map { homeRoute ->
HomeBottomNavigationItem(
modifier = Modifier.weight(1f),
selectIconResourceId = homeRoute.selectIconResourceId,
unSelectIconResourceId = homeRoute.unSelectIconResourceId,
title = homeRoute.title,
onClick = {
navController.navigate(homeRoute.route) {
popUpTo(0) { inclusive = true }
}
},
selected = navBackStackEntry?.destination?.route == homeRoute.route,
)
}
}
}

@Composable
private fun HomeBottomNavigationItem(
modifier: Modifier = Modifier,
selectIconResourceId: Int,
unSelectIconResourceId: Int,
title: String,
onClick: () -> Unit,
selected: Boolean,
) {
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()

val contentTintColor = when {
isPressed -> BitnagilTheme.colors.navy300
selected -> BitnagilTheme.colors.navy500
else -> BitnagilTheme.colors.navy100
}
val iconResourceId = if (selected) selectIconResourceId else unSelectIconResourceId

Column(
modifier = modifier.clickable(
onClick = onClick,
interactionSource = interactionSource,
indication = null,
),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
painter = painterResource(id = iconResourceId),
contentDescription = title,
modifier = Modifier.padding(4.dp).size(24.dp),
colorFilter = ColorFilter.tint(color = contentTintColor),
)

Text(
text = title,
style = BitnagilTheme.typography.caption2Medium,
color = contentTintColor,
)
}
}

@Composable
@Preview
private fun HomeBottomNavigationBarPreview() {
val navigator = rememberHomeNavigator()

HomeBottomNavigationBar(
navController = navigator.navController,

)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.threegap.bitnagil.navigation.home

import android.annotation.SuppressLint
import android.app.Activity
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.threegap.bitnagil.presentation.home.HomeScreenContainer
import com.threegap.bitnagil.presentation.mypage.MyPageScreenContainer
import com.threegap.bitnagil.presentation.recommendroutine.RecommendRoutineScreenContainer

@Composable
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
fun HomeNavHost(
modifier: Modifier = Modifier,
navigateToSetting: () -> Unit,
navigateToOnBoarding: () -> Unit,
navigateToNotice: () -> Unit,
navigateToQnA: () -> Unit,
navigateToRegisterRoutine: (String?) -> Unit,
navigateToEditRoutine: (String) -> Unit,
navigateToEmotion: () -> Unit,
) {
val navigator = rememberHomeNavigator()

DoubleBackButtonPressedHandler()
Comment thread
wjdrjs00 marked this conversation as resolved.

Scaffold(
modifier = Modifier.fillMaxSize(),
bottomBar = {
HomeBottomNavigationBar(navController = navigator.navController)
},
content = { _ ->
NavHost(
navController = navigator.navController,
startDestination = navigator.startDestination,
modifier = modifier,
) {
composable(HomeRoute.Home.route) {
HomeScreenContainer(
navigateToRegisterRoutine = {
navigateToRegisterRoutine(null)
},
navigateToEditRoutine = navigateToEditRoutine,
navigateToEmotion = navigateToEmotion,
)
}

composable(HomeRoute.RecommendRoutine.route) {
RecommendRoutineScreenContainer(
navigateToEmotion = navigateToEmotion,
navigateToRegisterRoutine = navigateToRegisterRoutine,
)
}

composable(HomeRoute.MyPage.route) {
MyPageScreenContainer(
navigateToSetting = navigateToSetting,
navigateToOnBoarding = navigateToOnBoarding,
navigateToNotice = navigateToNotice,
navigateToQnA = navigateToQnA,
)
}
}
},
)
}

@Composable
fun DoubleBackButtonPressedHandler() {
val context = LocalContext.current
var backPressedTimeMillis by remember { mutableLongStateOf(0L) }
BackHandler {
if (System.currentTimeMillis() - backPressedTimeMillis < 2000) {
backPressedTimeMillis = 0
(context as? Activity)?.finish()
} else {
backPressedTimeMillis = System.currentTimeMillis()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.threegap.bitnagil.navigation.home

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController

class HomeNavigator(
val navController: NavHostController,
) {
val startDestination = HomeRoute.Home.route
}

@Composable
fun rememberHomeNavigator(navController: NavHostController = rememberNavController()): HomeNavigator =
remember(navController) {
HomeNavigator(navController)
}
Loading