๊ฐœ๋ฐœ ์ผ์ง€ ๐Ÿ’ป/Nutri Capture

Nutri Capture ๋ฐฑ์—”๋“œ - ChatBar์— ViewModel ์—ฐ๊ฒฐ

interfacer_han 2025. 1. 2. 15:45

#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