Skip to content

Commit

Permalink
[FEAT/#26] 네비게이션 기본 세팅
Browse files Browse the repository at this point in the history
  • Loading branch information
angryPodo committed Jan 15, 2025
1 parent e6f74ad commit cf8ec80
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.spoony.spoony.core.designsystem.theme.SpoonyAndroidTheme
import com.spoony.spoony.presentation.dummy.DummyScreen
import com.spoony.spoony.presentation.main.MainScreen
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand All @@ -19,7 +19,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge()
setContent {
SpoonyAndroidTheme {
DummyScreen()
MainScreen()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.spoony.spoony.presentation.explore

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

@Composable
fun ExploreScreen() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Explore Screen",
fontSize = 50.sp
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.spoony.spoony.core.navigation.MainTabRoute
import com.spoony.spoony.presentation.map.navigaion.Map
import com.spoony.spoony.presentation.explore.ExploreScreen
import kotlinx.serialization.Serializable

fun NavController.navigateExplore(
Expand All @@ -15,13 +15,13 @@ fun NavController.navigateExplore(
navigate(Explore, navOptions)
}

fun NavGraphBuilder.ExploreNavGraph(
fun NavGraphBuilder.exploreNavGraph(
paddingValues: PaddingValues
) {
composable<Explore> {
ExploreScreen()
}
}


@Serializable
data object Explore : MainTabRoute
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.spoony.spoony.presentation.main

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
import com.spoony.spoony.core.navigation.Route
import com.spoony.spoony.presentation.explore.navigation.navigateExplore
import com.spoony.spoony.presentation.map.navigaion.Map
import com.spoony.spoony.presentation.map.navigaion.navigateMap
import com.spoony.spoony.presentation.register.navigation.navigateRegister

class MainNavigator(
val navController: NavHostController
) {
private val currentDestination: NavDestination?
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination

val startDestination = Map

val currentTab: MainTab?
@Composable get() = MainTab.find { tab ->
currentDestination?.hasRoute(tab::class) == true
}

fun navigate(tab: MainTab) {
val navOptions = navOptions {
navController.currentDestination?.route?.let {
popUpTo(it) {
inclusive = true
saveState = true
}
}
launchSingleTop = true
restoreState = true
}

when (tab) {
MainTab.MAP -> navController.navigateMap(navOptions)
MainTab.REGISTER -> navController.navigateRegister(navOptions)
MainTab.EXPLORE -> navController.navigateExplore(navOptions)
}
}

@Composable
fun shouldShowBottomBar() = MainTab.contains {
currentDestination?.hasRoute(it::class) == true
} && (currentTab?.showBottomSheet ?: true)

inline fun isCurrentDestination(destination: NavDestination): Boolean {
return navController.currentDestination == destination
}

inline fun <reified T : Route> NavHostController.isCurrentDestination() =
currentDestination?.hasRoute<T>() == true
}

@Composable
fun rememberMainNavigator(
navController: NavHostController = rememberNavController()
): MainNavigator = remember(navController) {
MainNavigator(navController)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.spoony.spoony.presentation.main

import android.app.Activity
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.compose.NavHost
import com.spoony.spoony.presentation.explore.navigation.exploreNavGraph
import com.spoony.spoony.presentation.main.component.MainBottomBar
import com.spoony.spoony.presentation.map.navigaion.mapNavGraph
import com.spoony.spoony.presentation.register.navigation.registerNavGraph
import kotlinx.collections.immutable.toPersistentList

@Composable
fun MainScreen(
navigator: MainNavigator = rememberMainNavigator()
) {
val context = LocalContext.current

var backPressedTime by remember {
mutableLongStateOf(0L)
}

BackHandler(enabled = true) {
if (System.currentTimeMillis() - backPressedTime <= 2000L) {
(context as Activity).finish()
} else {
// TODO: 스낵바 자리
}
backPressedTime = System.currentTimeMillis()
}

Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Scaffold(
bottomBar = {
MainBottomBar(
visible = navigator.shouldShowBottomBar(),
tabs = MainTab.entries.toPersistentList(),
currentTab = navigator.currentTab,
onTabSelected = {
navigator.navigate(it)
}
)
}
) { innerPadding ->
NavHost(
navController = navigator.navController,
startDestination = navigator.startDestination
) {
mapNavGraph()

exploreNavGraph(
paddingValues = innerPadding
)

registerNavGraph(
paddingValues = innerPadding
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ enum class MainTab(
val selectedIconResource: Int,
val unselectedIconResource: Int,
val contentDescription: String,
val route: MainTabRoute
val route: MainTabRoute,
val showBottomSheet: Boolean = true
) {
MAP(
selectedIconResource = R.drawable.ic_map_main400_24,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -35,13 +36,12 @@ import com.spoony.spoony.presentation.main.MainTab
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList


@Composable
fun MainBottomBar(
visible: Boolean,
tabs: ImmutableList<MainTab>,
currentTab: MainTab?,
onTabSelected: (MainTab) -> Unit,
onTabSelected: (MainTab) -> Unit
) {
AnimatedVisibility(
visible = visible,
Expand All @@ -66,11 +66,13 @@ fun MainBottomBar(
horizontalArrangement = Arrangement.SpaceEvenly
) {
tabs.forEach { tab ->
MainBottomBarItem(
tab = tab,
selected = (tab == currentTab),
onClick = { onTabSelected(tab) },
)
key(tab.route) {
MainBottomBarItem(
tab = tab,
selected = (tab == currentTab),
onClick = { onTabSelected(tab) }
)
}
}
}
}
Expand All @@ -81,7 +83,7 @@ fun MainBottomBar(
private fun RowScope.MainBottomBarItem(
tab: MainTab,
selected: Boolean,
onClick: () -> Unit,
onClick: () -> Unit
) {
Column(
modifier = Modifier
Expand All @@ -90,7 +92,7 @@ private fun RowScope.MainBottomBarItem(
indication = null,
role = null,
interactionSource = remember { MutableInteractionSource() },
onClick = onClick,
onClick = onClick
)
.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
Expand All @@ -106,7 +108,7 @@ private fun RowScope.MainBottomBarItem(
),
modifier = Modifier.size(24.dp),
contentDescription = tab.contentDescription,
tint = Color.Unspecified,
tint = Color.Unspecified
)
Text(
text = tab.contentDescription,
Expand All @@ -123,7 +125,7 @@ private fun RowScope.MainBottomBarItem(
@Preview
@Composable
private fun BottomBarPreview() {
SpoonyAndroidTheme{
SpoonyAndroidTheme {
Column(modifier = Modifier) {
MainBottomBar(
visible = true,
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/com/spoony/spoony/presentation/map/MapScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.spoony.spoony.presentation.map

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

@Composable
fun MapScreen() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Map Screen",
fontSize = 50.sp
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.spoony.spoony.presentation.map.navigaion

import androidx.compose.foundation.layout.PaddingValues
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.spoony.spoony.core.navigation.MainTabRoute
import com.spoony.spoony.presentation.map.MapScreen
import kotlinx.serialization.Serializable

fun NavController.navigateMap(
Expand All @@ -14,13 +14,12 @@ fun NavController.navigateMap(
navigate(Map, navOptions)
}

fun NavGraphBuilder.MapNavGraph(
paddingValues: PaddingValues
) {
fun NavGraphBuilder.mapNavGraph() {
composable<Map> {
MapScreen()
}
}


@Serializable
data object Map : MainTabRoute
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.spoony.spoony.presentation.register

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

@Composable
fun RegisterScreen() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Register Screen",
fontSize = 50.sp
)
}
}
Loading

0 comments on commit cf8ec80

Please sign in to comment.