#1 ๊ฐ์
#1-1 ViewModel ์ ๋ฌํ๊ธฐ
ChatBar์ '์ ์ก' ๋ฒํผ์ ๋๋ฌ, NutrientViewModel.onEvent()๋ฅผ ๋ฐ์์ํฌ ๊ฒ์ด๋ค. ํ์ฌ MainActivity์์ NutrientViewModel ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ NutrientScreen์ ์ ๋ฌํ๊ณ ์๋๋ฐ, ๊ฐ์ ๋ฐฉ์์ผ๋ก ChatBar์๋ ์ ๋ฌํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด NutrientViewModel์ ์ ์ํด๋ Insert ๋์์ด, ChatBar์ '์ ์ก' ๋ฒํผ์ ๋๋ฅผ ๋ ํธ๋ฆฌ๊ฑฐ๋๊ฒ ๋ง๋ ๋ค.
์ง๊ธ์ ๊ธฐ์กด ์ฝ๋๋ฅผ ๋ณต์ฌํด์ ์๋ก์ด ๊ธฐ๋ฅ์ ๋ถ์ฌ๋ฃ๊ธฐํ๊ณ ์์ง๋ง, ํ์ Hilt๋ก ๋ง์ด๊ทธ๋ ์ด์ ํด์ ์ด๋ฌํ ์์กด์ฑ ๊ด๋ จ ์ฝ๋๋ค์ ๊น๋ํ๊ฒ ์ ๋ฆฌํ ์์ ์ด๋ค.
#1-2 ๋ฌธ์ ์ : UI ์ ๋ฐ์ดํธ
ํ์ง๋ง #1-1๋ฅผ ํ๋ก์ ํธ์ ์ ์ฉํด๋, #3-1์์ ๋ณด๋ฏ UI๊ฐ ์ ๋ฐ์ดํธ ๋์ง ์๋๋ค. '+' ๋ฒํผ์ ๋๋ฅด๋ ๊ฒฝ์ฐ์๋ ์ ๋๋ ๊ฒ๊ณผ ๋์กฐ์ ์ผ๋ก ๋ง์ด๋ค.
...
class NutrientViewModel(private val repository: MainRepository) : ViewModel() {
// (1) ํ๋ฉด ํ์์ฉ State
private val _nutrientScreenState = mutableStateOf(
NutrientScreenState(
dayMeals = SnapshotStateList()
)
)
val nutrientScreenState: State<NutrientScreenState>
get() = _nutrientScreenState
...
}
...
๋ฌธ์ ์ ์์ธ์ NutrientViewModel์ด ๋ณด์ ํ๋ State์ ๊ตฌ์กฐ์ ์๋ค. ํ์ฌ์ ๊ตฌ์กฐ๋ '+ ๋ฒํผ ๋๋ฆผ ์ด๋ฒคํธ'๋ฅผ ๊ฐ์งํ ๊ฒฝ์ฐ์๋ง _nutrientScreenState์ ์์๋ฅผ ํ๋ํ๋ ํ ๋นํ๋ ๋ฐฉ์์ด๋ค. ๋ง์ฝ, ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ViewModel์ '+ ๋ฒํผ ๋๋ฆผ ์ด๋ฒคํธ' ์ธ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ๋๋ค๋ฉด _nutrientScreenState๋ ๋ณํ์ง ์์ ๊ฒ์ด๋ค.
State๋ฅผ StateFlow๋ก ๋ณ๊ฒฝํ๊ณ , ๊ทธ StateFlow๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ตฌ๋ ํ๊ฒ ๋ง๋ค์ด์ผ ํ๋ค. ๊ทธ๋ฌ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค StateFlow๊ฐ ์์์ ์ผ๋ก ๋ณ๊ฒฝ๋ ๊ฒ์ด๋ค. ์ด๋ ๊ฒ ๋ฐ๊พธ๋ฉด ํ์ฌ์ ๋ฐฉ์๋ณด๋ค ํจ์ฌ ํธํ๊ณ , ํจ์ฌ ๊น๋ํ๊ณ , ํจ์ฌ ์๋ฌ์ ์ฌ์ง๊ฐ ์ ๋ค.
๋ค์ ๊ฒ์๊ธ์์ ์ด ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ๋ค.
#2 ์ฝ๋
#2-1 MainActivity.kt
...
class MainActivity : ComponentActivity() {
private lateinit var dao: MainDAO
private lateinit var repository: MainRepository
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dao = MainDatabase.getInstance(application).mainDAO
repository = MainRepository(dao)
enableEdgeToEdge()
setContent {
NutricapturenewTheme {
...
Scaffold(
...
bottomBar = {
when (currentRoute) {
Destination.NutrientScreen.route -> NutrientChatBar(
viewModel(
factory = NutrientViewModelFactory(repository)
)
)
else -> MainNavigationBar(navController)
}
},
...
) { ...
NavHost(
...
) {
composable(route = Destination.NutrientScreen.route) {
NutrientScreen(
scope = scope,
snackbarHostState = snackbarHostState,
viewModel = viewModel(factory = NutrientViewModelFactory(repository))
)
}
...
}
}
}
}
}
@Composable
private fun MainNavigationBar(navController: NavHostController) {
...
}
@Composable
fun NutrientChatBar(viewModel: NutrientViewModel) {
Row(
...
) {
...
Box(
...
) {
FilledTonalIconButton(
onClick = {
viewModel.onEvent(
NutrientViewModelEvent.InsertMeal(
meal = Meal(
time = LocalTime.now(),
name = inputtedText.value,
nutritionInfo = NutritionInfo()
),
date = LocalDate.now()
)
)
inputtedText.value = ""
},
...
) {
...
}
}
}
}
}
...
composable(route = Destination.NutrientScreen.route) { ... } ์์ ์๋, dao ๋ฐ repository ์ด๊ธฐํ ์ฝ๋๋ฅผ ๋ฐ์ผ๋ก ๋นผ์ MainActivity ๋ด์์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ค. ์ด๊ธฐํ๋ onCreate()์์ ์งํํ๋ค.
#2-2 NutrientScreen.kt
...
@Composable
fun NutrientScreen(
...
) {
...
LazyColumn(
...
) {
...
items(...) { ... ->
...
Card(
...
) {
Box(
...
) {
Column(
...
) {
Text(
...
)
Text(
text = "name: ${dayMeal.name} mealId: ${dayMeal.mealId}",
...
)
}
...
}
}
}
}
}
TextField์ ์ ๋ ฅ๋ name์ ํ์ธํ ์ ์๋๋ก ์์ ํ๋ค.
#3 ์์ฑ๋ ์ฑ
#3-1 ์คํฌ๋ฆฐ์ท

#1-2 ์ฐธ์กฐ
#3-2 ์ด ๊ฒ์๊ธ ์์ ์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
#3-3 ๋ณธ ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ต์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
'๊ฐ๋ฐ ์ผ์ง ๐ป > Nutri Capture' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Nutri Capture ํ๋ก ํธ์๋ - ์์ด์ฝ ์ ์ (1์ฐจ) (0) | 2025.01.12 |
---|---|
Nutri Capture ๋ฐฑ์๋ - StateFlow๋ก ์ ํ (0) | 2025.01.02 |
Nutri Capture ๋ฐฉํฅ์ฑ - ๊ฐ๋ฐ ์ผ์ ํ (1์ฐจ) (0) | 2024.12.31 |
Nutri Capture ํ๋ก ํธ์๋ - Dimens์ ํจ๊ป ChatBar ๋ง๋ค๊ธฐ (0) | 2024.12.31 |
Nutri Capture ํ๋ก ํธ์๋ - Typography (2) | 2024.12.28 |