개발 일지/Nutri Capture 41

Nutri Capture 백엔드 - 이진 탐색 적용

#1 삽입 함수 리팩토링#1-1 리팩토링할 함수// in NutrientViewModel.ktprivate fun findIndexToInsert(list: SnapshotStateList, newItem: DayMealView): Int {    for(i: Int in list.indices) {        if(newItem NutrientViewModel에는 정렬된 배열에 새 원소를 삽입하는 함수 findIndexToInsert()가 있다. 기존 findIndexToInsert()는 위 코드에서 보듯 선택 정렬의 원리로 짰다. #1-2 이진 탐색 이진 탐색 (Binary search)#1 알고리즘 #1-1 #1-2 이렇게 해서 x의 인덱스 i를 찾으면 좋겠지만, 이 x가 배열 values 어디에..

Nutri Capture 프론트엔드 - item 추가ㆍ제거 애니메이션

#1 애니메이션LazyColumn에 아이템이 추가ㆍ제거될 때의 애니메이션 효과를 추가하려고 한다. 이 때, 그 구현 방식은 (당장 내가 보기에) 아래와 같이 2개로 나눌 수 있다. 2개의 공식 문서 링크를 달겠다. 각각은 서로 다른 구현 방식을 알려주고 있다. #1-1 'Composable'의 애니메이션 처리를 위한 가이드 애니메이션 수정자 및 컴포저블  |  Jetpack Compose  |  Android Developers이 페이지는 Cloud Translation API를 통해 번역되었습니다. 애니메이션 수정자 및 컴포저블 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Compose에는 일반적인developer.android.com가이드에 기술된 코드의 구조는 아래..

Nutri Capture 프론트엔드 - INSERT 및 DELETE 버튼 구현

#1 개요레코드를 INSERT하는 버튼과 DELETE하는 버튼을 각각 구현한다.  #2 코드 - 깨알 수정...@Composablefun NutrientScreen( ...) { ... LazyColumn( ... ) { ... itemsIndexed(...) { ... -> Card( ... elevation = CardDefaults.cardElevation(4.dp) ) { ... } } }}레코드 하나하나를 감싸는 Card의 그림자값을 줄인다. 그림자값이 8.dp면 다른 카드 영역에까..

Nutri Capture 백엔드 - DeleteDayMeal 이벤트 추가

#1 개요최근 프론트엔드에서는 DayMealView 테이블만을 사용하므로, NutrientViewModelEvent.kt에 정의해두었던 DeleteMeal()이 사용될 일이 없다. 따라서, DeleteDayMeal() 이벤트를 새로 만든다. #2 코드#2-1 NutrientViewModelEvent.kt...sealed class NutrientViewModelEvent { ... data class DeleteMeal(val meal: Meal) : NutrientViewModelEvent() data class DeleteDayMeal(val dayMeal: DayMealView) : NutrientViewModelEvent()}본 게시글의 목적과 별개로, NutrientViewMod..

Nutri Capture 백엔드 - DAO 논리적 오류 수정

#1 개요프로젝트의 데이터베이스(Room) 부분에서 작성했던 DAO 함수의 논리적 오류를 해결한다. #2 논리적 오류 - ORDER BY#2-1 문제 코드...@Daointerface MainDAO {    ...    @Query("SELECT * FROM DayMealView")    suspend fun getAllDayMeals(): List    @Query("SELECT * FROM DayMealView LIMIT :limit")    suspend fun getAllDayMeals(limit: Int): List    @Query("""    SELECT * FROM DayMealView     WHERE day_date     @Query("SELECT * FROM DayMealView W..

Nutri Capture 프론트엔드 - 무한 스크롤 로직 리팩토링

#1 문제#1-1 문제 상황정렬된 아이템이기에, 각 아이템의 시각은 위에서 아래로 갈수록 작아져야한다. 그러나, mealId 41인 아이템과 mealId 50인 아이템을 보면 이상한 점이 보인다. 바로 mealId 50인 아이템의 시각은 18:01:14...로, 17:09:03...인 mealId 50보다 큰 것이다. #1-2 문제 코드...@Composablefun NutrientScreen( ...) { LaunchedEffect(key1 = true) { ... } LaunchedEffect(key1 = true) { ... } LaunchedEffect(key1 = viewModel.isInitialized.value) { if..

Nutri Capture 백엔드 - Room 무결성 보완

#1 개요이전 게시글의 Commit은 앱 실행이 안되는 버그가 있다. 해당 버그를 발생시킨 근본적인 부분을 찾아간다. 특히, 세번째 에러는 Room의 무결성과 관련된 에러로 해결까지 꽤 시간이 소요됐으며, 동시에 Room 구현에 있어 DAO를 경솔히 작성해서는 안된다는 교훈을 내게 주었다. #2 코드 - 첫번째 에러#2-1 NoSuchElementExceptionFATAL EXCEPTION: main (Ask Gemini)Process: com.example.nutri_capture_new, PID: 7679java.util.NoSuchElementException: List is empty. at kotlin.collections.CollectionsKt___CollectionsKt.last(_C..

Nutri Capture 프론트엔드 - 채팅UI 구조 잡기

#1 개요이전 게시글에서 채팅 UI 도입을 위해 가상 테이블 DayMealView를 만들었다. 백엔드 작업이 끝났으므로, Day 테이블 및 Meal 테이블을 참조하던 프론트가 이제는 DayMealView 테이블을 참조하도록 만들어야 한다. #2 코드 - 백엔드 깨알 변경 사항#2-1 DAO에서 getAllDayMeals(limit: Int) 선언...@Daointerface MainDAO { ... @Query("SELECT * FROM DayMealView LIMIT :limit") suspend fun getAllDayMeals(limit: Int): List ...}존재하는 모든 레코드를 가져오는 getAllDayMeals()의 메소드 오버로딩이다. getAllDayMeals(..

Nutri Capture 백엔드 - Room 가상 테이블의 레코드를 필요한 만큼만 가져오기

#1 개요#1-1 우아함이전 게시글에서 만든, 가상 테이블을 참조하는 DAO 함수는 가상 테이블의 모든 레코드를 통째로 가져오는 방식이었다. 하지만 이는 우아함과는 거리가 있는 방식이다. 처음에는 화면을 가득 채울 정도의 레코드만 가져오고, 무한 스크롤을 통해서 필요한 만큼만 또 가져오는 방식을 구현할 것이다. "View가 보유한 마지막 레코드가 무엇인지 알고, 해당 레코드를 기반으로 (테이블 위치 상) 더 뒤에 있는 레코드들을 뽑아오면 될 것이다."라고 처음에는 간단하게만 생각했다. 그러나 시행착오를 겪으며 시간이 오래 걸렸다 (고작 DAO 함수하나 만드는 건데 이전 게시글과 별도의 게시글로 분리할 이유기도 하다). #1-2 첫 시도: Cursor Room DAO를 사용하여 데이터 액세스  |  And..

Nutri Capture 백엔드 - Room 가상 테이블 선언

#1 개요#1-1 채팅 UI 구현을 위한 첫 걸음'채팅 UI'에서 표시할 데이터를 하나의 레코드로서 가지는 가상 테이블을 선언한다. #1-2 가상 테이블 (SQLite)SELECT day_table.day_id AS day_id, meal_table.meal_id AS meal_id, day_table.day_date AS day_date, meal_table.meal_time AS meal_time, meal_table.meal_name AS meal_name, /* NutritionInfo의 Column 시작 */ meal_table.overeating_excess AS overeating_excess, meal_table...