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

Nutri Capture ํ”„๋ก ํŠธ์—”๋“œ - ์•„์ด์ฝ˜ ์ œ์ž‘ (1์ฐจ)

interfacer_han 2025. 1. 12. 23:09

#1 ๊ฐœ์š”

#1-1 ์ผ์ •

 

Nutri Capture ๋ฐฉํ–ฅ์„ฑ - ๊ฐœ๋ฐœ ์ผ์ •ํ‘œ (1์ฐจ)

#1 ํ˜„ ๊ฐœ๋ฐœ ํ–‰ํƒœ์— ๋Œ€ํ•œ ๋ฌธ์ œ์ #1-1 ๊ณผ์ •์˜ ์™„๋ฒฝ์ฃผ์˜๋‚œ ํ’‹๋‚ด๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋จธ์— ๋ถˆ๊ณผํ•˜๋‹ค. ๋‚ด๊ฐ€ ๋งŒ๋“ค ์•ฑ ๋˜ํ•œ ๊ทธ์ € ๊ทธ๋Ÿฐ ์•ฑ์ผ ๊ฒƒ์ด๋‹ค. ์ ์–ด๋„ ์ฒ˜์Œ (์ถœ์‹œํ•  ์˜๋„๋กœ ๋งŒ๋“œ๋Š”) ์•ฑ์„ ๋‹น์—ฐํžˆ ๊ทธ๋Ÿด ๊ฒƒ์ด๋‹ค,

kenel.tistory.com

์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ 'ChatBar๋ฅผ ํ†ตํ•ด ์ „์†กํ•œ MealItem์˜ name ์†์„ฑ์„ LazyColumn์—์„œ ํ™•์ธ'ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด์ œ ๋‹ค์Œ ์ž‘์—…์€ ๊ณ„ํšํ‘œ ์ƒ, 'nutritionInfo ๊ฐ ํ”„๋กœํผํ‹ฐ์— 1๋Œ€1๋กœ ๋Œ€์‘๋˜๋Š” ์•„์ด์ฝ˜์„ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ œ์ž‘ํ•จ'์ด๋‹ค.
 

#1-2 ์•„์ด์ฝ˜

์•„์ด์ฝ˜์„ ์–ด๋””์—์„œ ์ผ๊ด„์ ์œผ๋กœ ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ๊ฑธ ์ƒ๊ฐํ–ˆ์ง€๋งŒ, ์•„์ด์ฝ˜ ๊ฐ„ ํ†ต์ผ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง์ ‘ ๊ทธ๋ฆฌ๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋ฌผ๋ก , ๋„ˆ๋ฌด ๋งŽ์€ ์‹œ๊ฐ„์„ ํˆฌ์žํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์ด๊ฒŒ ์–ด๋–ค ์•„์ด์ฝ˜์ธ์ง€ ์•Œ์•„๋ณผ ์ˆ˜๋งŒ ์žˆ๋Š” ์ˆ˜์ค€์˜ ํ€„๋ฆฌํ‹ฐ๋ฉด ๋œ๋‹ค.
 

#1-3 Inkscape

 

Overview | Inkscape

Overview For Designers of all Kinds The design process may begin by doodles on a napkin, a sketched mindmap, a photo of a memorable object, or a mockup in software which really wouldn't work to complete the project. Inkscape can take you from this stage to

inkscape.org

๋ฌด๋ฃŒ ํ”„๋กœ๊ทธ๋žจ์ธ Inkscape๋ฅผ ํ†ตํ•ด SVG ์•„์ด์ฝ˜์„ ์ œ์ž‘ํ–ˆ๋‹ค.
 

#2 ์ œ์ž‘๋œ ์•„์ด์ฝ˜

๊ธ€ ์ฝ๋Š” ์ˆœ์„œ๋Œ€๋กœ data class์ธ NutritionInfo์˜ ํ”„๋กœํผํ‹ฐ 'overeatingExcess', 'fiberQuality', 'sodiumExcess', 'proteinQuality', 'flourExcess', 'refinedGrainExcess', 'refinedSugarExcess' ๋‹ค.

 

์•„์ด์ฝ˜์„ ์ œ์ž‘ํ•˜๋ฉด์„œ ๋“  ์ƒ๊ฐ์€, ๊ดœํžˆ ํšŒ์‚ฌ์— '๋””์ž์ด๋„ˆ'๋ผ๋Š” ์ง์ฑ…์ด ์žˆ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. '๋””์ž์ธ ์ž์›'(Asset) ์ œ์ž‘์€ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ 'ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜๋Š” ๊ฒธ์‚ฌ๊ฒธ์‚ฌ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ'์ด ์ ˆ๋Œ€ ์•„๋‹ˆ๋‹ค.

 

๋‚ด๊ฐ€ ๋งŒ๋“ค๊ธด ํ–ˆ์ง€๋งŒ ์œ„ ์•„์ด์ฝ˜๋“ค์ด ์ •๋ง ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์ด๋Ÿฐ ํ€„๋ฆฌํ‹ฐ์˜ ์•„์ด์ฝ˜์„ ํ”„๋กœ์ ํŠธ์— ๋„ฃ์–ด Commitํ•˜๋Š๋‹ˆ ์ฐจ๋ผ๋ฆฌ ์ฃฝ๊ณ  ์‹ถ์„ ์ •๋„๋‹ค. ๊ทธ ์ •๋„๋กœ ์ €ํ•ญ๊ฐ์ด ๊ฑฐ์…Œ๋‹ค. ํ•˜์ง€๋งŒ, ์ด ๊ฒฐ๊ณผ์˜ ์™„๋ฒฝ์ฃผ์˜๊ฐ€ ๋‚  ์ฃฝ์—ฌ์˜ค์ง€ ์•Š์•˜๋‚˜. ๋‚˜์ค‘์— ๋‹ค์‹œ ๊น”๋”ํ•œ ์•„์ด์ฝ˜์œผ๋กœ ๊ต์ฒดํ•  ๋‚ ์ด ์˜ฌ ๊ฒƒ์ด๋‹ค.

 

#3 ์ž‘๋™ ํ™•์ธ

#3-1 svg ํŒŒ์ผ ์ฒจ๋ถ€


์™„์„ฑ๋œ #2์˜ ์•„์ด์ฝ˜ svg ํŒŒ์ผ๋“ค์„ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์— ๋„ฃ๋Š”๋‹ค. [drawable ํด๋” ์šฐํด๋ฆญ] - [New] - [Vector Asset]์—์„œ svg ํŒŒ์ผ์„ ๋„ฃ์œผ๋ฉด, ์œ„์™€ ๊ฐ™์ด xml ํŒŒ์ผ ํ™•์žฅ์ž๋กœ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€๋œ๋‹ค.


#3-2 MainActivity.kt

...

class MainActivity : ComponentActivity() {

    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        setContent {
            NutricapturenewTheme {
                ...

                Scaffold(
                    ...
                    topBar = {
                        TopAppBar(
                            title = {
                                ...
                            },
                            actions = {
                                IconButton(
                                    onClick = {
                                        navController.navigate("statisticsScreen") {
                                            popUpTo(navController.graph.findStartDestination().id) {
                                                saveState = true
                                            }
                                            launchSingleTop = true
                                            restoreState = true
                                        }
                                    },
                                ) {
                                    Icon(
                                        painterResource(id = R.drawable.stacked_line_chart),
                                        contentDescription = "ํ†ต๊ณ„"
                                    )
                                }
                            }
                        )
                    },
                    ...
                    }
                ) { ...
                    ...
            }
        }
    }

    ...
}

...

#3-1์—์„œ ์ถ”๊ฐ€ํ•œ ์•„์ด์ฝ˜์„ StatisticsScreen์— ์ž„์‹œ๋กœ ๋‘˜ ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ์œ„ํ•ด, Top bar์— StatisticsScreen์œผ๋กœ ์ด๋™ํ•˜๋Š” ๋„ค์ด๊ฒŒ์ด์…˜ ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

 

#3-3 StatisticsScreen.kt

...

@Composable
fun StatisticsScreen(
    scope: CoroutineScope,
    snackbarHostState: SnackbarHostState
) {
    val nutrientIcons = arrayOf(
        painterResource(id = R.drawable.pan_tool_alt),
        painterResource(id = R.drawable.flour_excess),
        painterResource(id = R.drawable.fiber_quality),
        painterResource(id = R.drawable.sodium_excess),
        painterResource(id = R.drawable.protein_quality),
        painterResource(id = R.drawable.overeating_excess),
        painterResource(id = R.drawable.refined_grain_excess),
        painterResource(id = R.drawable.refined_sugar_excess)
    )

    LazyVerticalGrid(
        columns = GridCells.Adaptive(minSize = Dimens.IconButton.targetSize),
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        items(nutrientIcons) { nutrientIcon ->
            Box(
                modifier = Modifier.fillMaxSize()
            ) {
                FilledTonalIconButton(
                    onClick = {

                    },
                    modifier = Modifier
                        .size(Dimens.IconButton.targetSize)
                        .padding((Dimens.IconButton.targetSize - Dimens.IconButton.stateLayer) / 2) // ์ด padding() ์ œ๊ฑฐ ์‹œ, stateLayer๋Š” ์‚ฌ๋ผ์ง€๊ฒŒ ๋จ (= stateLayer๊ฐ€ targetSize์™€ ๋˜‘๊ฐ™์€ ํฌ๊ธฐ๊ฐ€ ๋จ)
                        .align(Alignment.Center)
                        //.background(Color.Red),
                ) {
                    Icon(
                        painter = nutrientIcon,
                        contentDescription = "test",
                        modifier = Modifier.size(Dimens.IconButton.iconSize)
                    )
                }
            }
        }
    }
}

LazyColumn๊ณผ ๋™์ผํ•œ ์ž‘๋™ ์›๋ฆฌ๋ฅผ ๊ฐ€์ง€๋Š” LazyVerticalGrid๋ฅผ ๋‘”๋‹ค.

 

#3-4 ์Šคํฌ๋ฆฐ์ƒท


๋งจ ์ขŒ์ธก ์ƒ๋‹จ์— ์žˆ๋Š” ์•„์ด์ฝ˜์€ ๊ตฌ๊ธ€์—์„œ ์ œ๊ณตํ•˜๋Š” ์•„์ด์ฝ˜์œผ๋กœ, ๋น„๊ต๋ฅผ ์œ„ํ•ด ๋„ฃ์—ˆ๋‹ค. ์ € ์ •๋„ ํ€„๋ฆฌํ‹ฐ๊ฐ€ ๋  ๋•Œ๊นŒ์ง€, ๋‚˜๋จธ์ง€ ์•„์ด์ฝ˜๋“ค์„ ์—…๋ฐ์ดํŠธ ํ•ด ๋‚˜๊ฐ„๋‹ค.
 

#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