
class DiaryActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val diaryDao = DiaryDatabase.getDatabase(application).diaryDao()
val repository = OfflineDiariesRepository(diaryDao)
val viewModelFactory = DiaryViewModelFactory(repository)
val diaryViewModel = ViewModelProvider(this, viewModelFactory)[DiaryViewModel::class.java]
setContent{
val navController = rememberNavController()
//ViewModel 선언
DiaryTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
SetupNavHost(navController = navController, viewModel = diaryViewModel)
}
}
}
}
}
@Composable
fun SetupNavHost(navController: NavHostController, viewModel: DiaryViewModel) {
NavHost(
navController = navController,
startDestination = "list"
) {
composable("list") {
DiariesListScreen(
viewModel,
onNavigateToCreate = {
navController.navigate("create")
},
onDiaryClick = { diaryId ->
navController.navigate("detail/$diaryId")
}
)
}
composable("create") {
DiaryEntryForm(
navController,viewModel
)
}
composable("detail/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) // 인자 정의
) { backStackEntry ->
// 인자 값을 가져와서 사용
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryDetailScreen(navController,viewModel = viewModel, id = id,onNavigateToUpdate = { diaryId ->
navController.navigate("update/$diaryId")
})
}
composable(
"update/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryUpdateForm(viewModel = viewModel, id = id)
}
}
}
@Composable
fun CalendarPicker(onDateSelected: (Date) -> Unit) {
val context = LocalContext.current
// 현재 날짜를 가져옵니다.
val today = Calendar.getInstance()
// 캘린더 아이콘을 클릭하면 DatePickerDialog를 표시합니다.
Icon(
imageVector = Icons.Filled.DateRange,
contentDescription = "Calendar",
modifier = Modifier
.size(40.dp)
.clickable {
// DatePickerDialog 표시, 현재 날짜(today)를 초기값으로 설정합니다.
DatePickerDialog(
context,
{ _, year, month, dayOfMonth ->
// 사용자가 날짜를 선택하면 콜백 함수를 호출합니다.
val selectedCalendar = Calendar
.getInstance()
.apply {
set(year, month, dayOfMonth)
}
onDateSelected(selectedCalendar.time) // 새로운 날짜를 반환합니다.
},
today.get(Calendar.YEAR),
today.get(Calendar.MONTH),
today.get(Calendar.DAY_OF_MONTH)
).show()
}
)
}
fun dateFormatter(selectedDate: String): LocalDateTime {
// 선택된 날짜를 LocalDateTime으로 변환
val date = LocalDate.parse(selectedDate, DateTimeFormatter.ISO_LOCAL_DATE)
// LocalDate를 LocalDateTime으로 변환하면서 시간을 0시 00분으로 설정
return LocalDateTime.of(date, LocalTime.MIDNIGHT)
}navHostController 를 인자로 전달받을 수 있는데 각각의 장 단점이 확실하고, 아직 Fragment 구성을 확실하게 하지 않아 두가지 방법 다 사용해 보았다.함수를 인자로 받는 경우
NavHostController를 직접 받는 경우
- 장점: 네비게이션 로직이 컴포저블 내부에서 직접 처리되므로, 관련 로직을 한눈에 볼 수 있고 관리가 용이합니다.
- 단점: 컴포저블의 재사용성이 다소 감소할 수 있으며, NavHostController에 대한 의존성이 커집니다.
어느 것이 더 효과적인지는 앱의 구조와 사용 사례에 따라 달라질 수 있습니다. 만약 네비게이션 로직이 복잡하고 여러 컴포저블에서 비슷한 네비게이션 동작이 필요한 경우, NavHostController를 직접 인자로 받는 것이 좋을 수 있습니다. 반면, 컴포저블을 다양한 상황에서 재사용하고자 하거나, 네비게이션 로직을 외부에서 제어하고 싶은 경우에는 함수를 인자로 받는 방식이 더 적합할 수 있습니다.
@Composable
fun SetupNavHost(navController: NavHostController, viewModel: DiaryViewModel) {
NavHost(
navController = navController,
startDestination = "list"
) {
composable("list") {
DiariesListScreen(
viewModel,
onNavigateToCreate = {
navController.navigate("create")
},
onDiaryClick = { diaryId ->
navController.navigate("detail/$diaryId")
}
)
}
composable("create") {
DiaryEntryForm(
navController,viewModel
)
}
composable("detail/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) // 인자 정의
) { backStackEntry ->
// 인자 값을 가져와서 사용
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryDetailScreen(navController,viewModel = viewModel, id = id,onNavigateToUpdate = { diaryId ->
navController.navigate("update/$diaryId")
})
}
composable(
"update/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryUpdateForm(viewModel = viewModel, id = id)
}
}
}
arguments 파라미터: 이 네비게이션 대상으로 전달되는 인자를 정의한다.listOf(navArgument("id") { type = NavType.IntType })는 id라는 이름의 인자를 정의하며, 이 인자의 타입이 Int임을 나타냄backStackEntry -> {...}: composable 함수에 대한 콜백으로, 네비게이션 대상이 활성화될 때 실행됨.backStackEntry는 이 네비게이션 대상으로 이동할 때의 상태를 포함하는 객체로 이 객체를 통해 인자 값을 가져올 수 있다.backStackEntry.arguments?.getInt("id") ?: return@composable:backStackEntry의 arguments에서 "id" 인자의 값을 Int로 가져온다.?.는 안전 호출 연산자로, arguments가 null이 아닐 때만 getInt("id")를 호출?:는 엘비스 연산자로, 왼쪽 표현식의 결과가 null일 경우 오른쪽 값을 사용, 여기서는 null일 경우 composable 람다 함수에서 반환하여 더 이상 진행하지 않음rememberNavController 함수가 Composable 함수이며, Compose UI의 컨텍스트에서 호출되어야 하기 때문에 setContent 안에서 호출 된다.setContent는 Compose UI 라이브러리를 사용하는 Android 애플리케이션에서 UI의 최상위 진입점을 정의한다.setContent 내에서 UI를 구성하는 Composable 함수들을 호출한다.