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

Nutri Capture ๋ฐฑ์—”๋“œ - NutritionInfo ๋ฆฌํŒฉํ† ๋ง

interfacer_han 2025. 3. 26. 21:43

#1 ๋ฌธ์ œ์ 

#1-1 ๋ฆฌํŒฉํ† ๋งํ•  ๊ธฐ์กด ์ฝ”๋“œ

package com.example.nutri_capture_new.db

import androidx.room.ColumnInfo

data class NutritionInfo(
    // ๊ณผ์‹ ์ •๋„๊ฐ’
    @ColumnInfo(name = "overeating_excess")
    var overeatingExcess: Int = 0,

    // ์ •์ œ๋‹น ์„ญ์ทจ ์ •๋„๊ฐ’
    @ColumnInfo(name = "refined_sugar_excess")
    var refinedSugarExcess: Int = 0,

    // ์ •์ œ ๊ณก๋ฌผ ์„ญ์ทจ ์ •๋„๊ฐ’
    @ColumnInfo(name = "refined_grain_excess")
    var refinedGrainExcess: Int = 0,

    // ๋ฐ€๊ฐ€๋ฃจ ์„ญ์ทจ ์ •๋„๊ฐ’
    @ColumnInfo(name = "flour_excess")
    var flourExcess: Int = 0,

    // ์„ฌ์œ ์งˆ ์„ญ์ทจ ์ •๋„๊ฐ’
    @ColumnInfo(name = "fiber_quality")
    var fiberQuality: Int = 0,

    // ๋‹จ๋ฐฑ์งˆ ์„ญ์ทจ ์ •๋„๊ฐ’
    @ColumnInfo(name = "protein_quality")
    var proteinQuality: Int = 0,

    // ๋‚˜ํŠธ๋ฅจ ์„ญ์ทจ ์ •๋„๊ฐ’
    @ColumnInfo(name = "sodium_excess")
    var sodiumExcess: Int = 0
)

 

#1-2 Column์˜ ์ด๋ฆ„์— ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋กœ์ง์ด ๋“ค์–ด๊ฐ

๊ธฐ์กด ์ฝ”๋“œ์—๋Š” ์ปฌ๋Ÿผ ์ด๋ฆ„์— excess๊ฐ€ ๋ถ™์œผ๋ฉด, '์ผ๋ฐ˜์ ์œผ๋กœ ๋งŽ์ด ๋จน์„์ˆ˜๋ก ๋‚˜์œ ๊ฒƒ', ์ปฌ๋Ÿผ ์ด๋ฆ„์— quality๊ฐ€ ๋ถ™์œผ๋ฉด, '์ผ๋ฐ˜์ ์œผ๋กœ ๋งŽ์œผ ๋จน์„์ˆ˜๋ก ์ข‹์€ ๊ฒƒ'์ด๋ผ๋Š” ๊ทœ์น™์ด ์žˆ์—ˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” ๋ถ„๋ช… ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์˜ ์ฝ”๋“œ๋‹ค. ๋”ฐ๋ผ์„œ ๋‚˜๋งŒ ์•Œ์•„๋ณด๋ฉด ๋˜๊ธด ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํ•ญ์ƒ '๋‚จ๋“ค์ด ๋ดค์„ ๋•Œ ์ง๊ด€์ ์ธ' ์ฝ”๋“œ๋ฅผ ์ง€ํ–ฅํ•ด์•ผ ํ•œ๋‹ค. ๋ถ„๋ช… ์–ธ์  ๊ฐ„ ํšŒ์‚ฌ์— ๋“ค์–ด๊ฐ€ ํŒ€ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๊ฒŒ ๋  ํ…Œ๋‹ˆ๊นŒ. ๋˜, ์‚ฌ์ •์ด ์ƒ๊ฒจ ๊ฐœ๋ฐœ์— ์˜ค๋žœ ๊ธฐ๊ฐ„ ์†์„ ๋–ผ๊ณ  ๋‹ค์‹œ ๊ฐœ๋ฐœํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๊ณค๋ž€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์–ด์จŒ๊ฑฐ๋‚˜, ์ด ๊ทœ์น™์„ ํ๊ธฐํ•œ๋‹ค.

 

#1-3 ์˜์–‘์†Œ๋ฅผ ์ˆœํšŒํ•˜๊ธฐ ๋ถˆํŽธํ•จ

๋ช…์ƒ‰์ด ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค์ธ๋ฐ, getter๋‚˜ setter๊ฐ€ ์—†๋‹ค. NutritionInfo ํด๋ž˜์Šค๋Š” ์˜ค๋กœ์ง€ Room์— ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์šฉ๋„๋กœ๋งŒ ์“ฐ์ด๊ณ  ์žˆ๋‹ค. ์ฆ‰, ๋„ˆ๋ฌด๋‚˜ ์ •์งํ•˜๊ณ  ์ˆœ๋ฐ•(?)ํ•˜๋‹ค. ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ NutritionInfo๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๊ฐ ์˜์–‘์†Œ๋ฅผ ์ˆœํšŒํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋ฐ˜๋“œ์‹œ ๋ฐœ์ƒํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ์กด ์ฝ”๋“œ์—๋Š” ๊ด€๋ จ๋œ ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค.

 

#2 ์ฝ”๋“œ ์Šค๋‹ˆํŽซ

#2-1 NutritionDetail ํด๋ž˜์Šค ์ถ”๊ฐ€

package com.example.nutri_capture_new.db

import androidx.room.ColumnInfo
import androidx.room.Ignore
import com.example.nutri_capture_new.R

data class NutritionDetail(
    @Ignore
    val name: String = "๊ธฐ๋ณธ ์ด๋ฆ„",

    @ColumnInfo(name = "value")
    var value: Int = 0,

    @Ignore
    val iconId: Int = R.drawable.default_nutrition,

    @Ignore
    val nutritionCategory: NutritionCategory = NutritionCategory.MODERATE
)

#1-1์˜ ๊ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ NutritionDetail์ด๋ผ๋Š” ์ด๋ฆ„์˜ ํด๋ž˜์Šค๋กœ ๊ฐ์Œ€ ๊ฒƒ์ด๋‹ค. name์€ ๋ง ๊ทธ๋Œ€๋กœ ์˜์–‘์†Œ์˜ ์ด๋ฆ„, value๋Š” ์„ญ์ทจ ์ •๋„๊ฐ’, iconId๋Š” ์˜์–‘์†Œ๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ์•„์ด์ฝ˜ ๋ฒกํ„ฐ ์ด๋ฏธ์ง€์˜ ๋ฆฌ์†Œ์Šค ID, nutritionCategory๋Š” ์˜์–‘์†Œ์˜ ๋ฒ”์ฃผ๋‹ค. NutritionCategory๋Š” enum class๋กœ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

package com.example.nutri_capture_new.db

enum class NutritionCategory {
    GOOD, // ๋งŽ์ด ๋จน์„์ˆ˜๋ก ์ข‹์€ ์˜์–‘์†Œ
    BAD, // ๋งŽ์ด ๋จน์„์ˆ˜๋ก ๋‚˜์œ ์˜์–‘์†Œ
    MODERATE // ์ ๋‹นํžˆ ๋จน์–ด์•ผ ์ข‹์€ ์˜์–‘์†Œ
}

NutritionCategory๋Š” #1-2์—์„œ ๋งํ•œ ๊ทœ์น™์„ ๋Œ€์‹ ํ•œ๋‹ค. 

 

 

#2-2 ๋ฆฌํŒฉํ† ๋งํ•œ ์ฝ”๋“œ

...

data class NutritionInfo(
    // ๊ณผ์‹ ์ •๋„๊ฐ’
    @Embedded(prefix = "overeating_")
    val overeating: NutritionDetail = NutritionDetail(
        name = "๊ณผ์‹ํ•œ ์ •๋„",
        value = 0,
        iconId = R.drawable.overeating,
        nutritionCategory = NutritionCategory.BAD
    ),

    // ์ •์ œ๋‹น ์„ญ์ทจ ์ •๋„๊ฐ’
    @Embedded(prefix = "refined_sugar_")
    val refinedSugar: NutritionDetail = NutritionDetail(
        name = "์ •์ œ๋‹น",
        value = 0,
        iconId = R.drawable.refined_sugar,
        nutritionCategory = NutritionCategory.BAD
    ),

    // ์ •์ œ ๊ณก๋ฌผ ์„ญ์ทจ ์ •๋„๊ฐ’
    @Embedded(prefix = "refined_grain_")
    val refinedGrain: NutritionDetail = NutritionDetail(
        name = "์ •์ œ ๊ณก๋ฌผ",
        value = 0,
        iconId = R.drawable.refined_grain,
        nutritionCategory = NutritionCategory.BAD
    ),

    // ๋ฐ€๊ฐ€๋ฃจ ์„ญ์ทจ ์ •๋„๊ฐ’
    @Embedded(prefix = "flour_")
    val flour: NutritionDetail = NutritionDetail(
        name = "๋ฐ€๊ฐ€๋ฃจ",
        value = 0,
        iconId = R.drawable.flour,
        nutritionCategory = NutritionCategory.BAD
    ),

    // ์„ฌ์œ ์งˆ ์„ญ์ทจ ์ •๋„๊ฐ’
    @Embedded(prefix = "fiber_")
    val fiber: NutritionDetail = NutritionDetail(
        name = "์‹์ด์„ฌ์œ ",
        value = 0,
        iconId = R.drawable.fiber,
        nutritionCategory = NutritionCategory.GOOD
    ),

    // ๋‹จ๋ฐฑ์งˆ ์„ญ์ทจ ์ •๋„๊ฐ’
    @Embedded(prefix = "protein_")
    val protein: NutritionDetail = NutritionDetail(
        name = "๋‹จ๋ฐฑ์งˆ",
        value = 0,
        iconId = R.drawable.protein,
        nutritionCategory = NutritionCategory.GOOD
    ),

    // ๋‚˜ํŠธ๋ฅจ ์„ญ์ทจ ์ •๋„๊ฐ’
    @Embedded(prefix = "sodium_")
    val sodium: NutritionDetail = NutritionDetail(
        name = "๋‚˜ํŠธ๋ฅจ",
        value = 0,
        iconId = R.drawable.sodium,
        nutritionCategory = NutritionCategory.BAD
    ),
)

NutritionCategory๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, ์ปฌ๋Ÿผ ์ด๋ฆ„์—์„œ "excess" ๋˜๋Š” "quality"๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. @Embedded ์–ด๋…ธํ…Œ์ด์…˜์˜ prefix ํ”„๋กœํผํ‹ฐ๋Š” ์ปฌ๋Ÿผ ์ด๋ฆ„์ด ์•„๋‹ˆ๋‹ค. ์–ด๋…ธํ…Œ์ด์…˜ ๊ตฌ์กฐ ์ƒ์˜ ์ž์‹ ์ค‘ @ColumnInfo ์–ด๋…ธํ…Œ์ด์…˜์ด ์กด์žฌํ•˜๋ฉด, ๊ทธ @ColumnInfo ์–ด๋…ธํ…Œ์ด์…˜์˜ name ํ”„๋กœํผํ‹ฐ ์•ž์— ๋ถ™๋Š” ์ ‘๋‘์‚ฌ๊ฐ€ ๋ฐ”๋กœ prefix๋‹ค.

 

๊ฐ€๋ น, NutritionInfo.sodium.value๋Š” "sodium_value"๋ผ๋Š” ์ปฌ๋Ÿผ์— ์ €์žฅ๋œ๋‹ค. NutritionInfo.sodium.value์— ๋ถ™์€ ์–ด๋…ธํ…Œ์ด์…˜์ด @ColumnInfo(name = "value")๊ฐ€ ์•„๋‹ˆ๋ผ @ColumnInfo(name = "sample")์ด์—ˆ๋‹ค๋ฉด "sodium_sample"์ด๋ผ๋Š” ์ด๋ฆ„์˜ ์ปฌ๋Ÿผ์— ์ €์žฅ๋˜์—ˆ์„ ๊ฒƒ์ด๋‹ค.

 

#2-3 getter ๋ฐ setter

...

data class NutritionInfo(
    ...
) {
    fun toMutableMap(): MutableMap<String, NutritionDetail> {
        return mutableMapOf(
            "overeating" to overeating,
            "refinedSugar" to refinedSugar,
            "refinedGrain" to refinedGrain,
            "flour" to flour,
            "fiber" to fiber,
            "protein" to protein,
            "sodium" to sodium
        )
    }

    fun updateNutritionDetail(nutritionKey: String, update: (Int) -> Int): NutritionInfo {
        val updatedMap = this.toMutableMap().apply {
            get(nutritionKey)?.let { detail ->
                this[nutritionKey] = detail.copy(value = update(detail.value))
            }
        }

        return NutritionInfo(
            overeating = updatedMap["overeating"] ?: this.overeating,
            refinedSugar = updatedMap["refinedSugar"] ?: this.refinedSugar,
            refinedGrain = updatedMap["refinedGrain"] ?: this.refinedGrain,
            flour = updatedMap["flour"] ?: this.flour,
            fiber = updatedMap["fiber"] ?: this.fiber,
            protein = updatedMap["protein"] ?: this.protein,
            sodium = updatedMap["sodium"] ?: this.sodium
        )
    }
}

getter๋Š” ๋ชจ๋“  ์˜์–‘์†Œ์˜ ์ˆœํšŒ๋ฅผ ์œ„ํ•จ์ด๋‹ค. setter๋Š” ๋ณด๊ธฐ์— ์•ฝ๊ฐ„ ์ง€์ €๋ถ„ํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์œ„์™€ ๊ฐ™์ด ์งฐ๋‹ค. ๋‚ด๊ฐ€ ๋ด๋„ ๊น”๋”ํ•œ ์ฝ”๋“œ๋Š” ์•„๋‹ˆ๊ธฐ์—, ์–ธ์  ๊ฐ„ ๋‹ค์‹œ ๋ฆฌํŒฉํ† ๋งํ•˜๊ฒŒ ๋  ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. ์ง€๊ธˆ์€ ๊ทธ์ € ๋– ์˜ค๋ฅด๋Š” ์ตœ์„ ์˜ ๋ฐฉ์‹์— ์ถฉ์‹คํ–ˆ๋‹ค.

 

#4 ์™„์„ฑ๋œ ์•ฑ

#4-1 ์ด ๊ฒŒ์‹œ๊ธ€ ์‹œ์ ์˜ Commit

 

GitHub - Kanmanemone/nutri-capture-new

Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.

github.com

 

#4-2 ๋ณธ ํ”„๋กœ์ ํŠธ์˜ ๊ฐ€์žฅ ์ตœ์‹  Commit

 

GitHub - Kanmanemone/nutri-capture-new

Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.

github.com