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

#3 - 기본 화면 전환 구현 #4

Merged
merged 7 commits into from
Dec 14, 2024
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
9 changes: 8 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id("chaeum.android.application")
id("chaeum.android.compose")
alias(libs.plugins.androidx.navigation.safeargs)
alias(libs.plugins.kotlin.serialization)
}

android {
Expand Down Expand Up @@ -32,4 +32,11 @@ dependencies {
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.ui)
implementation(libs.androidx.compose.navigation)
implementation(libs.kotlinx.serialization.json)

implementation(projects.feature.auth)
implementation(projects.feature.etc)
implementation(projects.feature.matching)
implementation(projects.feature.mypage)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.yapp.chaeum

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
Expand Down
33 changes: 4 additions & 29 deletions app/src/main/java/com/yapp/chaeum/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,19 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.yapp.chaeum.ui.App
import com.yapp.chaeum.ui.rememberAppState
import com.yapp.chaeum.ui.theme.ChaeumTheme

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
val appState = rememberAppState()
ChaeumTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
App(appState)
}
}
}
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ChaeumTheme {
Greeting("Android")
}
}
32 changes: 32 additions & 0 deletions app/src/main/java/com/yapp/chaeum/navigation/AppNavHost.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.yapp.chaeum.navigation

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import com.example.auth.navigation.AuthGraph
import com.example.auth.navigation.authNavGraph
import com.example.matching.navigation.navigateToMatchingDetailRoute
import com.yapp.chaeum.navigation.home.homeNavGraph
import com.yapp.chaeum.ui.AppState

@Composable
fun AppNavHost(
appState: AppState,
modifier: Modifier = Modifier,
) {
val navController = appState.navController

NavHost(
navController = navController,
startDestination = AuthGraph,
) {
authNavGraph(
onLoginSuccess = appState::navigateToHome,
)
homeNavGraph(
onNavigateToDetail = navController::navigateToMatchingDetailRoute,
onBack = navController::popBackStack,
modifier = modifier,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.yapp.chaeum.navigation

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Call
import androidx.compose.material.icons.outlined.Call
import androidx.compose.ui.graphics.vector.ImageVector
import com.example.etc.navigation.EtcRoute
import com.example.matching.navigation.MatchingGraphDest
import com.example.mypage.navigation.MyPageRoute
import kotlin.reflect.KClass

enum class TopLevelDestination(
val selectedIcon: ImageVector,
val unselectedIcon: ImageVector,
val iconText: String,
val titleText: String,
val route: KClass<*>,
) {
MATCHING(
selectedIcon = Icons.Filled.Call,
unselectedIcon = Icons.Outlined.Call,
iconText = "매칭",
titleText = "매칭",
route = MatchingGraphDest.MatchingRoute::class,
),
MYPAGE(
selectedIcon = Icons.Filled.Call,
unselectedIcon = Icons.Outlined.Call,
iconText = "마이페이지",
titleText = "마이페이지",
route = MyPageRoute::class,
),
ETC(
selectedIcon = Icons.Filled.Call,
unselectedIcon = Icons.Outlined.Call,
iconText = "ETC",
titleText = "ETC",
route = EtcRoute::class,
);

companion object {
val topLevelDestinations = entries
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.yapp.chaeum.navigation.home

import androidx.compose.ui.Modifier
import androidx.navigation.NavGraphBuilder
import androidx.navigation.navigation
import com.example.etc.navigation.etcScreen
import com.example.matching.navigation.MatchingGraph
import com.example.matching.navigation.matchingNavGraph
import com.example.mypage.navigation.myPageScreen
import kotlinx.serialization.Serializable

@Serializable
data object HomeGraph

fun NavGraphBuilder.homeNavGraph(
onNavigateToDetail: () -> Unit,
onBack: () -> Unit,
modifier: Modifier = Modifier,
) {
navigation<HomeGraph>(startDestination = MatchingGraph) {
matchingNavGraph(
onNavigateToDetail = onNavigateToDetail,
onBack = onBack,
modifier = modifier,
)
myPageScreen(modifier)
etcScreen(modifier)
}
}
82 changes: 82 additions & 0 deletions app/src/main/java/com/yapp/chaeum/ui/App.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.yapp.chaeum.ui

import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavDestination.Companion.hierarchy
import com.example.auth.navigation.AuthGraph
import com.yapp.chaeum.navigation.AppNavHost
import com.yapp.chaeum.navigation.TopLevelDestination
import kotlin.reflect.KClass

@Composable
fun App(
appState: AppState = rememberAppState(),
modifier: Modifier = Modifier,
) {
val currentDestination = appState.currentDestination

Scaffold(
bottomBar = {
if (currentDestination?.isInAuthGraph() == false) {
AppBottomBar(appState, currentDestination)
}
}
) { innerPadding ->
val contentModifier = modifier.padding(innerPadding)
AppNavHost(
appState = appState,
modifier = contentModifier,
)
}
}

@Composable
private fun AppBottomBar(
appState: AppState,
currentDestination: NavDestination?
) {
BottomNavigation(
modifier = Modifier.navigationBarsPadding()
) {
TopLevelDestination.topLevelDestinations.forEach { topLevelRoute ->
BottomNavigationItem(
icon = {
Icon(
imageVector = topLevelRoute.selectedIcon,
contentDescription = topLevelRoute.name
)
},
label = { Text(topLevelRoute.name) },
selected = currentDestination.isRouteInHierarchy(topLevelRoute.route),
onClick = {
appState.navigateToTopLevelDestination(topLevelRoute)
}
)
}
}
}

/**
* 현재 목적지가 AuthGraph 인지 확인하는 메서드
*/
private fun NavDestination?.isInAuthGraph(): Boolean =
this?.hierarchy?.any { destination ->
destination.route == AuthGraph::class.qualifiedName
} ?: false

/**
* 현재 목적지가 TopLeveLDestination 라우트에 속하는지 확인하는 메서드
*/
private fun NavDestination?.isRouteInHierarchy(route: KClass<*>): Boolean =
this?.hierarchy?.any {
it.hasRoute(route)
} ?: false
60 changes: 60 additions & 0 deletions app/src/main/java/com/yapp/chaeum/ui/AppState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.yapp.chaeum.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavDestination
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
import com.example.auth.navigation.AuthGraphDest
import com.example.etc.navigation.navigateToEtc
import com.example.matching.navigation.navigateToMatchingGraph
import com.example.mypage.navigation.navigateToMyPage
import com.yapp.chaeum.navigation.TopLevelDestination
import com.yapp.chaeum.navigation.home.HomeGraph

@Composable
fun rememberAppState(
navController: NavHostController = rememberNavController(),
): AppState {
return remember(navController) {
AppState(navController = navController)
}
}

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

fun navigateToHome() {
navController.navigate(HomeGraph) {
popUpTo(AuthGraphDest.AuthRoute) {
inclusive = true
}
launchSingleTop = true
restoreState = true
}
}

fun navigateToTopLevelDestination(
topLevelDestination: TopLevelDestination,
) {
val topLevelNavOptions = navOptions {
popUpTo(HomeGraph) {
saveState = true
}
launchSingleTop = true
restoreState = true
}

when (topLevelDestination) {
TopLevelDestination.MATCHING -> navController.navigateToMatchingGraph(topLevelNavOptions)
TopLevelDestination.MYPAGE -> navController.navigateToMyPage(topLevelNavOptions)
TopLevelDestination.ETC -> navController.navigateToEtc(topLevelNavOptions)
}
}
}
1 change: 0 additions & 1 deletion app/src/main/java/com/yapp/chaeum/ui/theme/Theme.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.yapp.chaeum.ui.theme

import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
Expand Down
3 changes: 1 addition & 2 deletions app/src/test/java/com/yapp/chaeum/ExampleUnitTest.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.yapp.chaeum

import org.junit.Assert.assertEquals
import org.junit.Test

import org.junit.Assert.*

/**
* Example local unit test, which will execute on the development machine (host).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.yapp.build.logic

import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.yapp.build.logic.libs
plugins {
id("chaeum.android.library")
id("chaeum.android.compose")
// id("org.jetbrains.kotlin.plugin.serialization")
}

android {
Expand All @@ -22,6 +23,7 @@ dependencies {
// implementation(project(":core:common-ui"))

val libs = project.extensions.libs
implementation(libs.findLibrary("kotlinx.serialization.json").get())
implementation(libs.findLibrary("androidx.compose.navigation").get())
implementation(libs.findLibrary("androidx.lifecycle.viewModelCompose").get())
implementation(libs.findLibrary("androidx.lifecycle.runtimeCompose").get())
Expand Down
1 change: 1 addition & 0 deletions feature/auth/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
8 changes: 8 additions & 0 deletions feature/auth/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
plugins {
id("chaeum.android.feature")
alias(libs.plugins.kotlin.serialization)
}

android {
namespace = "com.chaeum.auth"
}
Empty file added feature/auth/consumer-rules.pro
Empty file.
Loading
Loading