Skip to content

Conversation

@alswlekk
Copy link
Collaborator

@alswlekk alswlekk commented Jan 28, 2026

🔗 관련 이슈

📙 작업 설명

  • 네비게이션 인자로 Class 를 넘기는 부분이 존재해 뷰모델을 공유하거나 id 를 넘겨서 api를 호출하는 형식 등으로 리펙토링

📸 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
기능 설명 기능 설명

💬 추가 설명 or 리뷰 포인트 (선택)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 상세 화면들에 로딩 상태 표시 추가로 더 나은 사용자 경험 제공
    • 오류 발생 시 재시도 기능 추가
  • 개선 사항

    • 설정 및 상세 정보 화면의 네비게이션 성능 향상
    • 데이터 로딩 흐름 최적화로 더 빠른 화면 전환 실현

✏️ Tip: You can customize this high-level summary in your review settings.

alswlekk and others added 6 commits January 28, 2026 14:17
주요 변경사항:
- Route.kt: 모든 Route를 ID 기반으로 유지
- NavGraph.kt: typeMap 제거, 모든 composable에서 ID만 전달
- 화면들: DTO 파라미터 제거, ID 기반으로 변경
- ViewModel: StateFlow로 데이터 로드 (Repository 필터링)
- 상세 화면들: when 분기처리로 로딩/에러/데이터 상태 관리

신규 ViewModel:
- DetailNoticeViewModel: ID로 공지사항 로드
- DetailSubscribeViewModel: ID로 구독정보 로드

업데이트 ViewModel:
- DetailElderInfoViewModel: StateFlow 추가, loadElderDataById() 메서드 추가
- DetailHealthViewModel: 데이터 로드 로직 추가
- DetailMyDataViewModel: StateFlow 추가, 자동 로드
- DetailSubscribeViewModel: 신규 생성
- DetailNoticeViewModel: 신규 생성

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…dicare-Call/Medicare-Call-Android into refactor/optimization-navigation-#234
- DetailElderInfoViewModel에 isLoading StateFlow 추가 (HealthDetailScreen 패턴 동일화)
- loadElderDataById에서 로딩 상태 토글 구현
- processElderInfo 메서드 구현 (등록/수정 통합 처리)
  - elderId 파라미터 추가하여 ID 기반 업데이트
  - 수정 모드에서만 데이터 자동 재로드 (-1이 아닐 때)
- ElderDetailScreen에 CircularProgressIndicator import 추가
- ElderDetailScreen 상태 분기 처리 추가
  - 수정 모드 && 로딩 중: 로딩 인디케이터 표시
  - 등록 모드 또는 데이터 로드 완료: 폼 UI 표시
- processElderInfo 호출에 elderId 파라미터 전달

이제 모든 Detail Screen이 일관된 패턴으로 상태를 관리합니다 (로딩/에러/데이터).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…dicare-Call/Medicare-Call-Android into refactor/optimization-navigation-#234
@coderabbitai
Copy link

coderabbitai bot commented Jan 28, 2026

Walkthrough

이 PR은 설정 화면의 네비게이션 아키텍처를 리팩토링하여 DTO 객체 대신 원시 ID를 전달하도록 변경합니다. 화면에서 DTO를 직접 받는 대신 ID를 기반으로 ViewModel에서 데이터를 로드합니다.

Changes

Cohort / File(s) Summary
Navigation Infrastructure
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/navigation/SettingNavigation.kt, app/src/main/java/com/konkuk/medicarecall/ui/navigation/Route.kt, app/src/main/java/com/konkuk/medicarecall/ui/navigation/MainNavigator.kt, app/src/main/java/com/konkuk/medicarecall/ui/navigation/NavType.kt
DTO 기반 네비게이션을 ID 기반으로 변환. ElderDetailScreen, HealthDetailScreen 등의 네비게이션 함수가 이제 정수 ID를 전달하고, NotificationSetting/UserInfoSetting은 파라미터 없는 객체로 변경됨.
Elder Management Screens
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderInfoScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/HealthDetailScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/HealthInfoScreen.kt
화면 서명에서 DTO 수신을 ID 수신으로 변경. ViewModel을 통한 데이터 로드, 로딩/에러 상태 처리, collectAsStateWithLifecycle을 사용한 상태 관리 추가.
User & Subscription Settings
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/MyDetailScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/MyDataSettingScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingAlarmScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SubscribeDetailScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingsScreen.kt
MyInfoResponseDto 파라미터 제거 또는 ID 기반 로드로 변경. collectAsStateWithLifecycle을 사용한 상태 처리 추가. 로딩 UI 및 에러 처리 개선.
Announcement Screens
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementDetailScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementScreen.kt
noticeId 기반 로드로 변환. DetailNoticeViewModel을 통한 데이터 페칭. 로딩/에러 상태에 따른 조건부 렌더링.
ViewModel Enhancements
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailElderInfoViewModel.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailHealthViewModel.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailMyDataViewModel.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailNoticeViewModel.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailSubscribeViewModel.kt
ID 기반 데이터 로드 메서드 추가. 상태 노출(uiState, isLoading, errorMessage 등) 개선. 리포지토리 의존성 재구성.
Login & Home Screens State Updates
app/src/main/java/com/konkuk/medicarecall/ui/feature/login/carecall/screen/CallTimeScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/login/info/screen/LoginMyInfoScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/login/info/screen/LoginPhoneScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/login/info/screen/LoginVerificationScreen.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/homedetail/sleep/..., app/src/main/java/com/konkuk/medicarecall/ui/feature/homedetail/statehealth/screen/StateHealthDetailScreen.kt
collectAsStateWithLifecycle을 사용한 상태 관리로 변환. 직접 ViewModel 속성 접근을 로컬 상태 변수로 대체.
Cleanup & Dependencies
gradle/wrapper/gradle-wrapper.properties, app/src/main/java/com/konkuk/medicarecall/ui/feature/login/carecall/component/FirstTimeWheelPicker.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/login/carecall/viewmodel/CallTimeViewModel.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/EldersInfoViewModel.kt, app/src/main/java/com/konkuk/medicarecall/ui/feature/homedetail/navigation/HomeDetailNavGraph.kt
Gradle 버전 업데이트(8.13 → 9.1.0), 불필요한 import 제거, 코드 포매팅 정리.

Sequence Diagram

sequenceDiagram
    actor User as 사용자
    participant Nav as Navigation Layer
    participant Screen as Detail Screen
    participant VM as ViewModel
    participant Repo as Repository
    participant API as Backend API

    User->>Nav: navigate(elderId: Int)
    Nav->>Screen: ElderDetailScreen(elderId)
    Screen->>VM: LaunchedEffect { loadElderDataById(elderId) }
    VM->>Repo: getElders()
    Repo->>API: fetch all elders
    API-->>Repo: [EldersInfoResponseDto...]
    Repo-->>VM: data list
    VM->>VM: filter by elderId
    VM-->>Screen: uiState = elderData
    Screen->>Screen: render form with loaded data
    User->>Screen: click save
    Screen->>VM: processElderInfo(elderId, requestDto)
    VM->>Repo: updateElderInfo(request)
    Repo->>API: POST/PATCH update
    API-->>Repo: success
    Repo-->>VM: updated data
    VM->>VM: reload elderData
    VM-->>Screen: updated state
    Screen->>Nav: onBack()
    Nav->>User: navigate back
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

refactor

Suggested reviewers

  • ikseong00
  • alswlekk
  • librawish808

Poem

🗺️ ID로만 길을 물어, 맵 찾아 헤매지 말고
ViewModel이 데이터 챙겨주면 화면은 날렵하게
DTO 짐 벗어던지니, 네비게이션 한결 가벼워졌네
로딩 스핀 돌고 에러 잡으니, 견고한 UX 완성
리팩토링의 정석, 깔끔하게 끝! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Gradle 버전 업그레이드(8.13 → 9.1)가 발견되었으나, 이는 주요 리팩토링 범위 외 변경사항이며 회귀 위험이 있을 수 있습니다. Gradle 버전 변경의 필요성과 호환성을 재검토하세요. PR 기여자의 다운그레이드 고려사항과 일치하는지 확인하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 네비게이션 인자 전달 방식 최적화에 대한 리팩토링 작업을 명확하게 설명하고 있으며, 변경사항의 핵심 목표와 일치합니다.
Linked Issues check ✅ Passed PR의 코드 변경사항이 이슈 #234의 핵심 요구사항을 충족합니다: 네비게이션 인자로 DTO 클래스 전달 방식을 ID 기반 또는 ViewModel 공유 방식으로 리팩토링 완료, 불필요한 코드 제거 및 성능 최적화 달성.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingAlarmScreen.kt (1)

43-76: 로딩 전 토글 조작 시 변경이 저장되지 않을 수 있음
myDataInfo가 null인 초기 상태에서도 토글이 즉시 바뀌고 updateSettings는 no-op이라 사용자 입장에서 “저장된 듯 보이는” 상태가 될 수 있어요. 로딩 완료 전에는 토글을 비활성화하거나, onCheckedChange에서 null이면 무시하도록 가드하는 게 안전합니다.

✅ 예시 수정(가드 추가)
@@
-    val myDataInfo by myDataViewModel.myDataInfo.collectAsStateWithLifecycle()
+    val myDataInfo by myDataViewModel.myDataInfo.collectAsStateWithLifecycle()
+    val canEdit = myDataInfo != null
@@
                 SwitchButton(
                     checked = masterChecked,
                     onCheckedChange = { isChecked ->
+                        if (!canEdit) return@SwitchButton
                         // 4. 상태를 먼저 모두 변경하고,
                         masterChecked = isChecked
                         completeChecked = isChecked
                         abnormalChecked = isChecked
                         missedChecked = isChecked
                         // 5. 마지막에 변경된 최종 상태로 ViewModel을 호출합니다.
                         updateSettings()
                     },
                 )

다른 스위치 onCheckedChange에도 동일 가드를 적용해주세요.

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementScreen.kt`:
- Line 30: MainNavigator's navigateToNoticeDetail currently accepts a
NoticesResponseDto but AnnouncementScreen and SettingNavigation expect an Int
noticeId; update the MainNavigator.navigateToNoticeDetail signature to accept
noticeId: Int (replace NoticesResponseDto) and update all implementations/call
sites to pass the Int id instead of the DTO (locate usages in
AnnouncementScreen, SettingNavigation.navController.navigateToNoticeDetail
extension, and any other callers) so the types align and compilation succeeds.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt`:
- Around line 70-76: The isMale state is initialized as nullable
(mutableStateOf<Boolean?>(null)) causing submission to default to FEMALE despite
the UI showing “남성”; change its initialization to a non-null Boolean that
matches the UI default (e.g., mutableStateOf(true)) and ensure any places that
read isMale (submission logic, e.g., the function that maps isMale to
Elder.Gender or the submit handler) handle a non-null Boolean rather than
treating null as FEMALE; update all occurrences (including the similar blocks
referenced around lines 203-269) to use the non-null default and adjust mapping
code if it expects nullable.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/HealthInfoScreen.kt`:
- Around line 34-37: MainNavigator's legacy method navigateToHealthDetail
currently accepts an EldersHealthResponseDto but the app now passes an Int
(elderId) from HealthInfoScreen; update MainNavigator.navigateToHealthDetail to
accept an Int (or remove the unused DTO overload) and adjust any internal
routing/callback wiring to use the elderId, ensuring HealthInfoScreen's call
signature (navigateToHealthDetail: (Int) -> Unit) matches the navigator; search
for navigateToHealthDetail and EldersHealthResponseDto usages to update callers
and remove the obsolete DTO-based method.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/MyDataSettingScreen.kt`:
- Line 54: The MyDataSettingScreen callback signature was changed to
navigateToUserInfoSetting: () -> Unit but MainNavigator still declares
navigateToUserInfoSetting(myInfo: MyInfoResponseDto), causing a mismatch; update
MainNavigator's declaration (and all implementing classes/usages) to a
no-argument function named navigateToUserInfoSetting with no MyInfoResponseDto
parameter, and adjust all call sites (implementations, overrides, and
invocations) to call navigateToUserInfoSetting() instead of passing a
MyInfoResponseDto so the interface and MyDataSettingScreen match.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingsScreen.kt`:
- Line 48: SettingsScreen defines navigateToNotificationSetting as a no-arg
callback but MainNavigator still exposes navigateToNotificationSetting(myInfo:
MyInfoResponseDto), causing a signature mismatch; update MainNavigator's method
(and any implementing classes) to a no-argument function named
navigateToNotificationSetting so it matches SettingsScreen, remove the
MyInfoResponseDto parameter from MainNavigator.navigateToNotificationSetting and
adjust all call sites and implementations that previously passed
MyInfoResponseDto to instead obtain needed info inside the navigator or via
another agreed mechanism.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailElderInfoViewModel.kt`:
- Around line 62-63: The Log.d call in DetailElderInfoViewModel currently prints
the full updateInfo (and similarly the request at lines 82-83), which may
contain sensitive data; change these logs to avoid exposing PII by logging only
a non-sensitive identifier (e.g., elderId) or a sanitized/masked representation
(e.g., mask phone/name) instead of the full updateInfo/request objects, and
centralize masking via a helper (e.g., maskSensitiveFields(updateInfo) or log
only updateInfo.id) so both the Log.d("DetailElderInfoViewModel", ...) at the
updateInfo site and the similar log at the request site no longer output raw
personal data.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailMyDataViewModel.kt`:
- Around line 32-45: The loadMyData function leaves _isLoading true if
getMyInfo() throws; wrap the repository call inside a try/finally in
viewModelScope.launch so _isLoading.value is set true before the call and always
set to false in the finally block; update the loadMyData implementation (around
viewModelScope.launch { ... }) to use try { userRepository.getMyInfo()... }
catch { ... } finally { _isLoading.value = false } and keep setting
_errorMessage in the catch/onFailure path and _myDataInfo on success.
🧹 Nitpick comments (3)
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailHealthViewModel.kt (1)

28-45: 로딩 플래그가 예외 상황에서 해제되지 않을 수 있음
Repository 호출이 예외를 던지면 _isLoading이 true로 남을 여지가 있어요. try/finally로 해제 보장하면 더 안전합니다.

✅ 예시 수정(try/finally)
 fun loadHealthInfoById(elderId: Int) {
     _isLoading.value = true
     _errorMessage.value = null
     viewModelScope.launch {
-        eldersHealthInfoRepository.getEldersHealthInfo()
-            .onSuccess { list ->
-                val elderHealth = list.firstOrNull { it.elderId == elderId }
-                _healthData.value = elderHealth
-                if (elderHealth == null) {
-                    _errorMessage.value = "건강 정보를 찾을 수 없습니다"
-                }
-            }
-            .onFailure { exception ->
-                _errorMessage.value = "건강 정보를 불러오지 못했습니다: ${exception.message}"
-                Log.e("DetailHealthViewModel", "건강 정보 로딩 실패", exception)
-            }
-        _isLoading.value = false
+        try {
+            eldersHealthInfoRepository.getEldersHealthInfo()
+                .onSuccess { list ->
+                    val elderHealth = list.firstOrNull { it.elderId == elderId }
+                    _healthData.value = elderHealth
+                    if (elderHealth == null) {
+                        _errorMessage.value = "건강 정보를 찾을 수 없습니다"
+                    }
+                }
+                .onFailure { exception ->
+                    _errorMessage.value = "건강 정보를 불러오지 못했습니다: ${exception.message}"
+                    Log.e("DetailHealthViewModel", "건강 정보 로딩 실패", exception)
+                }
+        } finally {
+            _isLoading.value = false
+        }
     }
 }
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/HealthDetailScreen.kt (1)

84-133: 초기/빈 상태 분기 추가 권장
isLoading=false, errorMessage=null, healthData=null 조합이면 화면이 비어 보일 수 있어요. 안전하게 else 분기 하나만 추가해도 UX가 안정됩니다.

✅ 간단한 fallback 예시
         when {
             isLoading && healthData == null -> {
                 // Loading state
                 Column(
                     modifier = Modifier
                         .fillMaxSize()
                         .padding(20.dp),
                     verticalArrangement = Arrangement.Center,
                     horizontalAlignment = Alignment.CenterHorizontally,
                 ) {
                     CircularProgressIndicator()
                     Spacer(modifier = Modifier.height(16.dp))
                     Text("건강정보를 불러오는 중입니다...")
                 }
             }

             errorMessage != null -> {
                 // Error state
                 Column(
                     modifier = Modifier
                         .fillMaxSize()
                         .padding(20.dp),
                     verticalArrangement = Arrangement.Center,
                     horizontalAlignment = Alignment.CenterHorizontally,
                 ) {
                     Text(
                         text = errorMessage ?: "오류가 발생했습니다",
                         color = MediCareCallTheme.colors.negative,
                         style = MediCareCallTheme.typography.M_17,
                     )
                     Spacer(modifier = Modifier.height(20.dp))
                     CTAButton(
                         type = CTAButtonType.GREEN,
                         text = "다시 시도",
                         onClick = {
                             detailViewModel.loadHealthInfoById(elderId)
                         },
                     )
                 }
             }

             healthData != null -> {
                 // Data loaded state
                 HealthDetailContent(
                     healthInfoResponseDto = healthData!!,
                     detailViewModel = detailViewModel,
                     onBack = onBack,
                 )
             }
+            else -> {
+                Column(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .padding(20.dp),
+                    verticalArrangement = Arrangement.Center,
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                ) {
+                    Text("데이터를 불러오지 못했습니다.")
+                }
+            }
         }
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/navigation/SettingNavigation.kt (1)

33-34: 매직 넘버(-1) 상수화 제안.
신규 등록 모드를 나타내는 값은 상수로 두면 의미가 더 명확해집니다.

♻️ 제안 변경
+private const val NEW_ELDER_ID = -1
+
-fun NavController.navigateToElderPersonalDetail(elderId: Int = -1) {
+fun NavController.navigateToElderPersonalDetail(elderId: Int = NEW_ELDER_ID) {
     navigate(Route.ElderPersonalDetail(elderId))
 }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
app/src/main/java/com/konkuk/medicarecall/ui/feature/login/carecall/screen/CallTimeScreen.kt (1)

31-33: 사용하지 않는 import 제거 필요

파이프라인에서 mutableIntStateOf, mutableStateOf, remember import가 사용되지 않는다고 플래그되었습니다. ViewModel로 상태 관리를 이전하면서 더 이상 필요하지 않은 것으로 보입니다.

🧹 수정 제안
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
app/src/main/java/com/konkuk/medicarecall/ui/feature/homedetail/sleep/screen/SleepDetailScreen.kt (2)

64-73: 스텁 함수의 미사용 파라미터들이 CI 실패를 유발하고 있어요.

// TODO: UI ... 주석으로 보아 아직 구현 예정인 함수인 것 같은데, 파이프라인에서 UnusedParameter 에러가 발생하고 있습니다.

당장 구현 계획이 없다면 함수를 제거하거나, 파라미터에 @Suppress("UnusedParameter") 어노테이션을 추가하는 방법을 고려해보세요.

💡 임시 해결 방안

Option 1: Suppress 어노테이션 추가

+@Suppress("UNUSED_PARAMETER")
 `@Composable`
 fun SleepDetailScreen(
     modifier: Modifier = Modifier,
     sleep: SleepUiState = SleepUiState(),
     onBack: () -> Unit = {},
     onDateSelected: (LocalDate) -> Unit = {},
     onMonthClick: () -> Unit = {},
 ) {
     // TODO: UI ...
 }

Option 2: 사용하지 않는 함수 제거

-@Composable
-fun SleepDetailScreen(
-    modifier: Modifier = Modifier,
-    sleep: SleepUiState = SleepUiState(),
-    onBack: () -> Unit = {},
-    onDateSelected: (LocalDate) -> Unit = {},
-    onMonthClick: () -> Unit = {},
-) {
-    // TODO: UI ...
-}

35-51: elderId 파라미터가 실제로 사용되고 있지 않네요.

다만 확인해보니 SleepViewModel은 이미 네비게이션 라우트의 SavedStateHandle을 통해 elderId를 추출하고 있습니다 (라인 51). 그래서 loadSleepDataForDate() 메서드는 elderId 파라미터를 받지 않는 구조네요.

이 경우 몇 가지 옵션이 있습니다:

  1. 추천: 불필요한 elderId 파라미터를 제거하기 (ViewModel이 이미 라우트에서 처리하므로)
  2. 아니면 이것이 의도적인 설계라면, 문서화가 필요할 수 있습니다

현재 구조에서는 제안하신 diff의 loadSleepDataForDate(elderId, selectedDate) 형태로 수정할 수 없습니다.

app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderInfoScreen.kt (1)

29-29: 사용하지 않는 import 제거 필요

CI 파이프라인에서 EldersInfoResponseDto import가 사용되지 않는다고 감지되었습니다. ID 기반 네비게이션으로 변경되면서 더 이상 명시적으로 필요하지 않습니다.

🔧 제안하는 수정
-import com.konkuk.medicarecall.data.dto.response.EldersInfoResponseDto
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingSubscribeScreen.kt (1)

27-27: 사용하지 않는 import 제거 필요

CI 파이프라인에서 EldersSubscriptionResponseDto import가 사용되지 않는다고 감지되었습니다.

🔧 제안하는 수정
-import com.konkuk.medicarecall.data.dto.response.EldersSubscriptionResponseDto
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingsScreen.kt (1)

36-36: 파이프라인 실패: 사용되지 않는 import 제거 필요

MyInfoResponseDto import가 사용되지 않아 CI가 실패하고 있습니다. 이제 myInfo가 ViewModel의 StateFlow에서 직접 수집되므로 이 import는 더 이상 필요하지 않습니다.

🔧 수정 제안
-import com.konkuk.medicarecall.data.dto.response.MyInfoResponseDto
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/MyDataSettingScreen.kt (1)

42-42: 파이프라인 실패: 사용되지 않는 import 제거 필요

MyInfoResponseDto import가 사용되지 않아 CI가 실패하고 있습니다.

🔧 수정 제안
-import com.konkuk.medicarecall.data.dto.response.MyInfoResponseDto
app/src/main/java/com/konkuk/medicarecall/ui/feature/login/info/screen/LoginMyInfoScreen.kt (1)

31-34: CI 실패 원인: 사용하지 않는 import 제거 필요.
NoUnusedImports가 발생하니 미사용 import 정리 부탁드려요.

🧹 제안 수정
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt`:
- Around line 257-268: The name validation currently uses
name.matches(Regex("^[가-힣a-zA-Z]*$")) which allows an empty string; update the
condition in the CTA button type expression so name cannot be empty — either
change the regex to use + (e.g., "^[가-힣a-zA-Z]+$") or add name.isNotEmpty() to
the combined predicate used to decide CTAButtonType.GREEN (the block referencing
name.matches(...), birth.isValidDate(), phoneNum checks, and isMale != null).
- Around line 109-116: The LaunchedEffect that listens to isSuccess won't
retrigger if isSuccess stays true, and deleteElderInfo() never sets success, so
navigation may not occur on subsequent operations; after handling navigation in
the LaunchedEffect
(navController.previousBackStackEntry?.savedStateHandle?.set("ELDER_NAME_UPDATED",
name) and onBack()), reset the backing flag (_isSuccess) to false so isSuccess
toggles for future operations, and update the ViewModel methods
processElderInfo(), updateElderInfo(), and deleteElderInfo() so they set
_isSuccess = true on success (and the first two also ensure _isSuccess is reset
immediately after the LaunchedEffect handles it), or alternatively convert
isSuccess to a one-shot event (SharedFlow/Channel/Event wrapper) to guarantee
single consumption.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/HealthDetailScreen.kt`:
- Line 7: Remove the unused import androidx.compose.foundation.layout.Row from
HealthDetailScreen.kt to fix the CI failure; locate the import statement
referencing Row at the top of the file (unused symbol: Row) and delete it so the
file only imports actually used Compose layout types.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SettingAlarmScreen.kt`:
- Around line 61-76: The updateSettings lambda can read stale composition state
right after setXChecked; change updateSettings to accept the new push-toggle
values as parameters and use those parameters when calling
myDataViewModel.updateUserData instead of reading
masterChecked/completeChecked/abnormalChecked/missedChecked from closure; update
all callers (the toggle handlers at the locations noted) to pass the immediate
boolean/new "ON"/"OFF" values into updateSettings, and ensure you construct
PushNotificationDto from those arguments when copying myDataInfo in
updateSettings (refer to updateSettings, myDataViewModel.updateUserData,
myDataInfo, and PushNotificationDto).

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/SubscribeDetailScreen.kt`:
- Around line 134-137: SubscribeDetailContent 함수의 onBack 파라미터가 사용되지 않아 빌드가 실패하고
있으니, 호출부와 함께 파라미터를 제거하거나(더 간단) 또는 확인 버튼 클릭 시 뒤로가기 동작으로 활용하도록 수정하세요; 구체적으로는
SubscribeDetailContent 선언에서 onBack 매개변수를 삭제하고 모든 호출지에서 해당 인자 전달을 제거하거나, 만약 뒤로가기
동작을 의도했다면 Compose 내의 확인 버튼 클릭 핸들러(예: 확인 버튼의 onClick)에서 onBack을 호출하도록
SubscribeDetailContent 선언과 버튼 클릭 로직을 연결하고 호출부는 그대로 두세요.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailElderInfoViewModel.kt`:
- Around line 52-53: The CI failure is due to ktlint requiring a blank line
between declarations and the following comment/declaration; in
DetailElderInfoViewModel locate the closing brace shown before the "// UI State"
comment and insert a single empty line between that brace (the previous
declaration) and the "// UI State" comment/declaration so there is a blank line
separating declarations per ktlint rules.

In `@gradle.properties`:
- Around line 24-33: The gradle.properties flags need alignment with AGP 9+
expectations: ensure android.newDsl and android.builtInKotlin are set together
(keep both false for now or both true) and add a short migration TODO noting
they will be removed in AGP 10.0; remove or move
android.defaults.buildfeatures.resvalues from this global file into per-module
build.gradle.kts files where resValues are actually required; update
android.enableAppCompileTimeRClass to true to match the new default; keep
monitoring the other flags (android.usesSdkInManifest.disallowed,
android.uniquePackageNames, android.dependency.useConstraints) and add a comment
summarizing these decisions for future AGP upgrades.

In `@gradle/libs.versions.toml`:
- Line 2: Update the project's Java and Kotlin target settings from 11 to 17+:
change any occurrences of sourceCompatibility = JavaVersion.VERSION_11 and
targetCompatibility = JavaVersion.VERSION_11 to JavaVersion.VERSION_17 (or
higher) and update any kotlinOptions.jvmTarget = "11" to "17" (or higher);
ensure build scripts that set javaToolchain or org.gradle.jvmargs are aligned to
Java 17, and verify CI/build agents use JDK 17+ so AGP 9.0.0 and Gradle 9.1.0
can run.
🧹 Nitpick comments (4)
app/src/main/java/com/konkuk/medicarecall/ui/feature/homedetail/statehealth/screen/StateHealthDetailScreen.kt (1)

56-76: 로딩 상태 처리는 깔끔해졌네요. 에러 상태 처리도 고려해보시면 좋을 것 같아요.

isLoading을 직접 Boolean으로 사용하는 변경은 위임자 패턴과 일관성 있게 잘 적용되었습니다.

한 가지 선택적 제안: AI 요약에 따르면 ViewModel에 errorMessage StateFlow가 있는 것으로 보이는데, 현재 화면에서는 에러 상태를 처리하지 않고 있어요. 네트워크 실패 등의 상황에서 사용자에게 피드백을 제공하는 것이 UX 관점에서 좋을 수 있습니다.

💡 에러 상태 처리 추가 예시 (선택사항)
val isLoading by viewModel.isLoading.collectAsStateWithLifecycle()
val errorMessage by viewModel.errorMessage.collectAsStateWithLifecycle()

// ... 기존 코드 ...

when {
    isLoading -> Box(
        Modifier
            .fillMaxSize()
            .background(color = MediCareCallTheme.colors.white),
    ) {
        CircularProgressIndicator(
            modifier = Modifier.align(Alignment.Center),
            color = MediCareCallTheme.colors.main,
        )
    }
    errorMessage != null -> {
        // 에러 UI 표시
    }
    else -> StateHealthDetailScreenLayout(...)
}
app/src/main/java/com/konkuk/medicarecall/ui/navigation/Route.kt (1)

59-60: 등록/수정 통합을 위한 기본값 사용이 적절함

elderId = -1을 기본값으로 사용해 등록(신규)과 수정(기존) 흐름을 통합한 설계가 좋습니다. 다만, 매직 넘버 -1 대신 상수로 정의하면 의도가 더 명확해질 수 있어요.

companion object {
    const val CREATE_NEW_ELDER = -1
}

필수는 아니지만 참고해주세요~

app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt (2)

100-105: 빈 catch 블록은 디버깅을 어렵게 만들 수 있어요.

날짜 파싱 실패 시 예외가 조용히 무시되어 birth 필드가 빈 상태로 남습니다. 최소한 로그를 남기거나, 원본 값을 그대로 사용하는 폴백 처리를 추가하면 좋겠어요.

🔧 수정 제안
             // 날짜 형식 변환 (yyyy-MM-dd -> yyyyMMdd)
             try {
                 val parseDate = LocalDate.parse(it.birthDate)
                 birth = parseDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"))
             } catch (e: Exception) {
-                // 파싱 실패 시 기존 값 유지하거나 빈 값 처리
+                // 파싱 실패 시 원본에서 숫자만 추출해서 사용
+                birth = it.birthDate.filter { char -> char.isDigit() }.take(8)
             }

303-308: toDashedDate 함수를 private으로 변경하거나 유틸 파일로 이동하는 것을 고려해 보세요.

현재 top-level public 함수로 선언되어 있는데, 이 파일 내에서만 사용된다면 private으로 제한하는 게 좋고, 여러 곳에서 재사용한다면 공통 유틸 파일로 분리하는 게 관리하기 편해요.

Comment on lines +109 to 116
// 작업 성공(등록/수정/삭제) 시 네비게이션 처리
LaunchedEffect(isSuccess) {
if (isSuccess) {
// 변경된 이름을 이전 화면으로 전달 (Toast 메시지 등을 위해)
navController.previousBackStackEntry?.savedStateHandle?.set("ELDER_NAME_UPDATED", name)
onBack()
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# ElderDetailScreen.kt 파일 위치 확인
fd -t f "ElderDetailScreen.kt" --full-path

# 파일 내용 확인 (전체)
fd -t f "ElderDetailScreen.kt" --full-path -x cat -n {}

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 15587


🏁 Script executed:

# DetailElderInfoViewModel 파일 찾기
fd -t f "DetailElderInfoViewModel.kt" --full-path

# 파일 크기 확인
fd -t f "DetailElderInfoViewModel.kt" --full-path -x wc -l {}

# 파일 내용 확인
fd -t f "DetailElderInfoViewModel.kt" --full-path -x cat -n {}

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 9997


🏁 Script executed:

# 더블 체크: deleteElderInfo 메서드와 isSuccess 관계 확인
rg -n "_isSuccess" app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailElderInfoViewModel.kt

# LaunchedEffect 사용 패턴 다시 확인
rg -n "LaunchedEffect.*isSuccess" app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt -A 5

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 668


isSuccess 상태 리셋 로직 필수

isSuccess가 성공 후 false로 리셋되지 않아서, 같은 화면에서 두 번째 작업을 하면 네비게이션이 작동하지 않습니다. LaunchedEffect는 의존성(isSuccess)이 실제로 변할 때만 재실행되는데, true 상태로 유지되면 두 번째 작업도 true → true가 되어 트리거되지 않기 때문입니다.

추가로 deleteElderInfo()_isSuccess를 설정하지 않아서 삭제 작업 후에도 화면이 돌아가지 않습니다.

해결책:

  • processElderInfo()updateElderInfo() 성공 후 네비게이션 처리 직후 _isSuccess 리셋
  • deleteElderInfo() 성공 시에도 _isSuccess = true 설정
  • 또는 isSuccess를 일회성 이벤트로 변경 (SharedFlow, Channel, Event wrapper 등)
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt`
around lines 109 - 116, The LaunchedEffect that listens to isSuccess won't
retrigger if isSuccess stays true, and deleteElderInfo() never sets success, so
navigation may not occur on subsequent operations; after handling navigation in
the LaunchedEffect
(navController.previousBackStackEntry?.savedStateHandle?.set("ELDER_NAME_UPDATED",
name) and onBack()), reset the backing flag (_isSuccess) to false so isSuccess
toggles for future operations, and update the ViewModel methods
processElderInfo(), updateElderInfo(), and deleteElderInfo() so they set
_isSuccess = true on success (and the first two also ensure _isSuccess is reset
immediately after the LaunchedEffect handles it), or alternatively convert
isSuccess to a one-shot event (SharedFlow/Channel/Event wrapper) to guarantee
single consumption.

Comment on lines 24 to 33
android.defaults.buildfeatures.resvalues=true
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
android.enableAppCompileTimeRClass=false
android.usesSdkInManifest.disallowed=false
android.uniquePackageNames=false
android.dependency.useConstraints=true
android.r8.strictFullModeForKeepRules=false
android.r8.optimizedResourceShrinking=false
android.builtInKotlin=false
android.newDsl=false
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

AGP 9.0.0 android.defaults.buildfeatures.resvalues android.newDsl android.builtInKotlin deprecated removed

💡 Result:

In Android Gradle Plugin (AGP) 9.0.0 (January 2026):

  • android.defaults.buildfeatures.resvalues

    • Not removed in 9.0.0, but its default changes from truefalse (so resValues is no longer enabled globally by default).
    • Migration: enable it only where needed:
      android {
        buildFeatures {
          resValues = true
        }
      }

    [1]

  • android.newDsl

    • Not removed in 9.0.0; its default changes from falsetrue.
    • Setting android.newDsl=false is a temporary opt-out to keep legacy DSL/variant API behavior, but this opt-out is planned to be removed in AGP 10.0 (mid‑2026).
      [1]
  • android.builtInKotlin

    • Not removed in 9.0.0; its default changes from falsetrue (built-in Kotlin enabled by default).
    • If you previously applied org.jetbrains.kotlin.android / kotlin-android, you generally need to remove that plugin and follow the built-in Kotlin migration steps; you can temporarily opt out with android.builtInKotlin=false (and the docs note you also need android.newDsl=false to opt out cleanly).
      [1][2]

Sources: AGP 9.0.0 release notes [1] and “Migrate to built-in Kotlin” guide [2].


🌐 Web query:

Android Gradle Plugin 9.0.0 gradle.properties deprecated flags migration guide

💡 Result:

For Android Gradle Plugin (AGP) 9.0.0 (January 2026), the “deprecated flags in gradle.properties” work is mainly about removing global/legacy toggles and moving configuration into per-module DSL.

1) Remove flags that AGP 9.0.0 no longer supports (will break the build)

AGP 9.0.0 errors out if these are set in gradle.properties (delete them):

  • android.r8.integratedResourceShrinking
  • android.enableNewResourceShrinker.preciseShrinking (resource shrinking is now always precise and integrated with R8) [1]

2) Remove flags that were deleted (no longer recognized) and migrate to module DSL

AGP 9.0.0 removed these global “defaults” flags (delete them), and enable features only in modules that actually need them via android { buildFeatures { ... } }:

  • android.defaults.buildfeatures.aidl → in the relevant module(s): buildFeatures { aidl = true }
  • android.defaults.buildfeatures.renderscript → in the relevant module(s): buildFeatures { renderScript = true } [1]

3) Expect default flips (may require opting out temporarily during migration)

AGP 9.0.0 changes defaults for several gradle.properties switches; if you were relying on old behavior, set an explicit value while you migrate (then remove the opt-out later):

  • android.newDsl now defaults to true (legacy android.applicationVariants/old variant API not accessible). Temporary opt-out: android.newDsl=false [1]
  • android.builtInKotlin now defaults to true (built-in Kotlin enabled by default; AGP has a runtime dependency on KGP 2.2.10). You must migrate or opt out. [1][2]
  • android.defaults.buildfeatures.resvalues now defaults to false → enable per module: buildFeatures { resValues = true } [1]
  • android.defaults.buildfeatures.shaders now defaults to false → enable per module: buildFeatures { shaders = true } [1]

Quick checklist

  1. Search gradle.properties for android.r8.integratedResourceShrinking and android.enableNewResourceShrinker.preciseShrinkingdelete. [1]
  2. Search for android.defaults.buildfeatures.*delete removed ones; move to android { buildFeatures { ... } } in only the modules that need them. [1]
  3. If upgrading breaks third-party plugins/build logic, temporarily set android.newDsl=false, then update plugins and remove the opt-out. [1]

Sources: AGP 9.0.0 release notes and AGP release page. [1][2]


🌐 Web query:

AGP 9.0 enableAppCompileTimeRClass builtInKotlin newDsl support status

💡 Result:

AGP 9.0 (9.0.0, January 2026) support/status of the flags

  • android.enableAppCompileTimeRClass: Supported. In AGP 9.0 its default changes to true (apps compile against a non-final R class). You can opt out by setting it back to false if needed. [1]

  • android.builtInKotlin: Supported and enabled by default in AGP 9.0 (you no longer need to apply org.jetbrains.kotlin.android / kotlin-android just to compile Kotlin). You can temporarily opt out via android.builtInKotlin=false, but Google notes this opt-out won’t be available in a future AGP 9.x release (before AGP 10.0). Also, opting out requires opting out of the new DSL (android.newDsl=false) because the Kotlin Android plugin is not compatible with the new DSL. [1][2]

  • android.newDsl: Supported. In AGP 9.0 its default changes to true (new DSL interfaces; legacy variant API like android.applicationVariants is no longer accessible). You can opt out with android.newDsl=false. [1]

Sources: Android Developers AGP 9.0.0 release notes [1] and “Migrate to built-in Kotlin” guide [2].


AGP 9.0.0에서 설정 플래그들은 여전히 지원되지만, 일부 임시 옵트-아웃에 대한 마이그레이션 계획 필요

라인 24-33의 플래그들은 AGP 9.0.0에서 제거되지 않았습니다. 다만 주의할 점:

  • android.newDsl=falseandroid.builtInKotlin=false반드시 함께 설정되어야 하며, 이는 AGP 10.0(2026년 중반 예정)에서 제거될 예정입니다. 향후 마이그레이션 계획을 세우세요.
  • android.defaults.buildfeatures.resvalues는 기본값이 truefalse로 변경되었습니다. 필요한 모듈에서만 per-module DSL로 설정하는 것이 좋습니다.
  • android.enableAppCompileTimeRClass는 기본값이 falsetrue로 변경되었습니다.

나머지 플래그들(android.usesSdkInManifest.disallowed, android.uniquePackageNames, android.dependency.useConstraints 등)도 현재 지원되지만, AGP 진화 과정에서 지속적으로 모니터링하세요.

🤖 Prompt for AI Agents
In `@gradle.properties` around lines 24 - 33, The gradle.properties flags need
alignment with AGP 9+ expectations: ensure android.newDsl and
android.builtInKotlin are set together (keep both false for now or both true)
and add a short migration TODO noting they will be removed in AGP 10.0; remove
or move android.defaults.buildfeatures.resvalues from this global file into
per-module build.gradle.kts files where resValues are actually required; update
android.enableAppCompileTimeRClass to true to match the new default; keep
monitoring the other flags (android.usesSdkInManifest.disallowed,
android.uniquePackageNames, android.dependency.useConstraints) and add a comment
summarizing these decisions for future AGP upgrades.

@@ -1,5 +1,5 @@
[versions]
agp = "8.13.0"
agp = "9.0.0"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Android Gradle Plugin 9.0.0 compatibility requirements Gradle version Java version Kotlin version

💡 Result:

Android Gradle Plugin (AGP) 9.0.0 compatibility requirements

  • Gradle: 9.1.0 (minimum and default) [1]
  • Java (JDK): 17 (minimum and default) [1]
  • Kotlin: AGP 9.0 enables built-in Kotlin by default and has a runtime dependency on Kotlin Gradle Plugin (KGP) 2.2.10 (minimum for built-in Kotlin; older KGP versions are auto-upgraded to 2.2.10) [2]

Notes

  • Gradle 9.x itself requires JVM 17+ to run the Gradle daemon, which aligns with AGP’s JDK 17 requirement. [3]

Sources:
[1] Android Developers — AGP 9.0.0 release notes (Compatibility table)
[2] Android Developers — AGP 9.0.0 release notes (Built-in Kotlin / KGP 2.2.10)
[3] Gradle Docs — Upgrading to Gradle 9.0.0 (JVM 17+ requirement)


🏁 Script executed:

# Find and examine gradle configuration files
find . -type f -name "libs.versions.toml" -o -name "gradle.properties" -o -name "build.gradle.kts" | head -20

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 168


🏁 Script executed:

cat -n gradle/libs.versions.toml

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 5011


🏁 Script executed:

cat -n gradle.properties

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 2049


🏁 Script executed:

head -100 build.gradle.kts

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 483


🏁 Script executed:

find . -name "gradle-wrapper.properties" -type f

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 121


🏁 Script executed:

cat -n gradle/wrapper/gradle-wrapper.properties

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 352


🏁 Script executed:

grep -A 5 -B 5 "java\|jdk\|sourceCompatibility\|targetCompatibility\|toolchain" build.gradle.kts app/build.gradle.kts

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 836


Java 버전 업그레이드 필수 (11 → 17 이상)

AGP 9.0.0과 Gradle 9.1.0은 Java 17 이상을 필요로 하는데, 현재 프로젝트는 sourceCompatibility = JavaVersion.VERSION_11, targetCompatibility = JavaVersion.VERSION_11, jvmTarget = "11"로 설정되어 있습니다. Java 버전을 17 이상으로 업그레이드하세요.

참고: Kotlin 2.2.20과 Compose BOM 2024.09.00은 AGP 9.0.0과 호환되므로 추가 변경이 필요 없습니다.

🤖 Prompt for AI Agents
In `@gradle/libs.versions.toml` at line 2, Update the project's Java and Kotlin
target settings from 11 to 17+: change any occurrences of sourceCompatibility =
JavaVersion.VERSION_11 and targetCompatibility = JavaVersion.VERSION_11 to
JavaVersion.VERSION_17 (or higher) and update any kotlinOptions.jvmTarget = "11"
to "17" (or higher); ensure build scripts that set javaToolchain or
org.gradle.jvmargs are aligned to Java 17, and verify CI/build agents use JDK
17+ so AGP 9.0.0 and Gradle 9.1.0 can run.

…dicare-Call/Medicare-Call-Android into refactor/optimization-navigation-#234
…dicare-Call/Medicare-Call-Android into refactor/optimization-navigation-#234
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/navigation/SettingNavigation.kt`:
- Around line 161-162: Remove the consecutive blank lines causing the Detekt
NoConsecutiveBlankLines violation by collapsing extra empty lines around the
composable<Route.NoticeDetail> block and the other affected region (the block
around lines 184–186); locate the composable<Route.NoticeDetail> declaration in
SettingNavigation.kt and ensure there is only a single blank line between
adjacent statements/blocks so the file has no back-to-back empty lines.

In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementDetailScreen.kt`:
- Around line 116-121: The unused onBack parameter causes a Detekt
UnusedParameter error; remove the onBack parameter from the
AnnouncementDetailContent invocation and from the AnnouncementDetailContent
composable signature (and any intermediate forwarding parameters) or
alternatively implement its usage; specifically update the call site in
AnnouncementDetailScreen (where AnnouncementDetailContent(noticeInfo =
noticeData!!, onBack = onBack) is used) and the corresponding
AnnouncementDetailContent composable declaration to either accept and invoke
onBack or drop the onBack parameter entirely so no unused parameter remains.
🧹 Nitpick comments (1)
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailElderInfoViewModel.kt (1)

132-134: 매직 넘버 -1 사용

elderId != -1로 수정 모드를 구분하고 있는데, 의도가 명확하지 않을 수 있습니다. 상수나 sealed class로 표현하면 가독성이 향상됩니다.

💡 예시
companion object {
    const val NEW_ELDER_ID = -1
}

// 사용 시
if (elderId != NEW_ELDER_ID) {
    loadElderDataById(elderId)
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt`:
- Around line 137-147: The current condition mixes loading and missing-data
states so when isEditMode && elderData == null the UI shows an infinite
CircularProgressIndicator; separate the branches so isEditMode && isLoading
shows the spinner (Column + CircularProgressIndicator) but handle isEditMode &&
elderData == null && !isLoading by rendering a clear empty/error state with a
message and a retry action (e.g., a Button) that calls the same loader function;
update the when block around isEditMode/isLoading/elderData to include an
explicit null/failure branch and ensure any retry invokes the loader used to
populate elderData.

Comment on lines +137 to +147
when {
// 수정 모드인데 데이터가 로딩 중이거나 아직 없을 때
isEditMode && (isLoading || elderData == null) -> {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
CircularProgressIndicator()
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

편집 모드에서 데이터 미존재 시 무한 로딩으로 고정될 수 있어요.

elderData == null 조건이 로딩과 묶여 있어, 실패/미존재 상황에서도 스피너가 계속 노출됩니다. 실패 분기를 분리해 재시도/안내 UI를 주세요.

🛠️ 수정 제안
-        when {
-            // 수정 모드인데 데이터가 로딩 중이거나 아직 없을 때
-            isEditMode && (isLoading || elderData == null) -> {
-                Column(
-                    modifier = Modifier.fillMaxSize(),
-                    horizontalAlignment = Alignment.CenterHorizontally,
-                    verticalArrangement = Arrangement.Center,
-                ) {
-                    CircularProgressIndicator()
-                }
-            }
-
-            else -> {
+        when {
+            // 수정 모드에서 로딩 중
+            isEditMode && isLoading -> {
+                Column(
+                    modifier = Modifier.fillMaxSize(),
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                    verticalArrangement = Arrangement.Center,
+                ) {
+                    CircularProgressIndicator()
+                }
+            }
+            // 수정 모드인데 데이터가 없을 때(오류/미존재)
+            isEditMode && elderData == null -> {
+                Column(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .padding(20.dp),
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                    verticalArrangement = Arrangement.Center,
+                ) {
+                    Text("데이터를 불러오지 못했습니다.")
+                    Spacer(modifier = Modifier.height(16.dp))
+                    CTAButton(
+                        type = CTAButtonType.GREEN,
+                        text = "다시 시도",
+                        onClick = { detailViewModel.loadElderDataById(elderId) },
+                    )
+                }
+            }
+            else -> {
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/ElderDetailScreen.kt`
around lines 137 - 147, The current condition mixes loading and missing-data
states so when isEditMode && elderData == null the UI shows an infinite
CircularProgressIndicator; separate the branches so isEditMode && isLoading
shows the spinner (Column + CircularProgressIndicator) but handle isEditMode &&
elderData == null && !isLoading by rendering a clear empty/error state with a
message and a retry action (e.g., a Button) that calls the same loader function;
update the when block around isEditMode/isLoading/elderData to include an
explicit null/failure branch and ensure any retry invokes the loader used to
populate elderData.

@ProtossManse
Copy link
Collaborator

코드는 문제 없는 것 같습니다! ci만 체크해주세요~
그리고, AGP가 8.13.0 -> 9.0.0으로 업그레이드 된 거 같은데, 호환성 등 여러가지 문제를 생각하면 그냥 8.13.0 버전을 사용하는게 좋지 않을까 싶습니다..!

@ProtossManse ProtossManse changed the title [Refactor] 네비게이션 인자 전달 방식 최적화 [Refactor] 네비게이션 인자 전달 방식 최적화 #234 Jan 29, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementDetailScreen.kt`:
- Around line 75-122: The when block lacks a fallback for the initial state
(isLoading=false, noticeData=null, errorMessage=null) causing a blank screen;
add a final else branch (or change to if/elseChain) that renders a sensible
fallback UI (e.g., a loading/empty state with a message and CTAButton) and/or
triggers detailViewModel.loadNoticeById(noticeId) so users can retry,
referencing isLoading, noticeData, errorMessage, AnnouncementDetailContent,
CTAButton and detailViewModel.loadNoticeById to locate where to add the new
branch.
🧹 Nitpick comments (2)
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/viewmodel/DetailMyDataViewModel.kt (1)

55-78: onFailure에서 CancellationException 처리가 updateUserData와 일관되지 않아요.

updateUserData 함수(Line 96-98)에서는 onFailure 콜백 내에서 CancellationException을 확인하고 다시 throw하는데, loadMyInfo에서는 이 처리가 빠져있습니다. 만약 getMyInfo()Result.failure(CancellationException)을 반환하는 경우, 불필요한 에러 메시지가 설정될 수 있습니다.

♻️ 일관성을 위한 수정 제안
                 .onFailure { exception ->
+                    if (exception is CancellationException) {
+                        throw exception
+                    }
                     _errorMessage.value = "내 정보를 불러오지 못했습니다: ${exception.message}"
                     Log.e("DetailMyDataViewModel", "내 정보 로딩 실패", exception)
                 }
app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementDetailScreen.kt (1)

171-177: Preview에서 Koin 의존으로 실패 가능
@Preview에서 AnnouncementDetailScreen() 호출 시 koinViewModel()이 주입되지 않아 프리뷰가 깨질 수 있어요. 프리뷰 전용으로 AnnouncementDetailContent에 더미 데이터를 넣거나, 프리뷰용 detailViewModel을 주입하는 형태로 분리하면 안정적입니다.

Comment on lines +75 to +122
when {
isLoading && noticeData == null -> {
// Loading state
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(16.dp))
Text("공지사항을 불러오는 중입니다...")
}
}

errorMessage != null -> {
// Error state
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = errorMessage ?: "오류가 발생했습니다",
color = MediCareCallTheme.colors.negative,
style = MediCareCallTheme.typography.M_17,
)
Spacer(modifier = Modifier.height(20.dp))
CTAButton(
type = CTAButtonType.GREEN,
text = "다시 시도",
onClick = {
detailViewModel.loadNoticeById(noticeId)
},
)
}
}

noticeData != null -> {
// Data loaded state
AnnouncementDetailContent(
noticeInfo = noticeData!!,
)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find DetailNoticeViewModel file
find . -type f -name "*DetailNoticeViewModel*"

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 177


🏁 Script executed:

# Search for DetailNoticeViewModel definition
rg "class\s+DetailNoticeViewModel" -A 20

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 3002


🏁 Script executed:

# Check errorMessage property and its handling
rg "errorMessage" -B 2 -A 2 --type kotlin

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 34464


🏁 Script executed:

# Find loadNoticeById implementation
rg "loadNoticeById" -B 2 -A 15 --type kotlin

Repository: Medicare-Call/Medicare-Call-Android

Length of output: 7055


초기 상태에서 화면 공백 문제 해결 필요

현재 when 블록은 isLoading=false, noticeData=null, errorMessage=null인 초기 상태에 매칭되는 조건이 없어 화면이 비는 구간이 생길 수 있어요. errorMessage 초기화는 잘 구현되어 있지만, 데이터 우선 표시와 fallback 상태를 추가하는 게 안전합니다.

🛠️ 개선 예시
-        when {
-            isLoading && noticeData == null -> {
+        when {
+            noticeData != null -> {
+                // Data loaded state
+                AnnouncementDetailContent(
+                    noticeInfo = noticeData!!,
+                )
+            }
+            isLoading -> {
                 // Loading state
                 Column(
                     modifier = Modifier
                         .fillMaxSize()
                         .padding(20.dp),
@@
-            errorMessage != null -> {
+            errorMessage != null -> {
                 // Error state
                 Column(
                     modifier = Modifier
                         .fillMaxSize()
                         .padding(20.dp),
@@
-            noticeData != null -> {
-                // Data loaded state
-                AnnouncementDetailContent(
-                    noticeInfo = noticeData!!,
-                )
-            }
+            else -> {
+                // Fallback (e.g., initial/idle)
+                Column(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .padding(20.dp),
+                    verticalArrangement = Arrangement.Center,
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                ) {
+                    CircularProgressIndicator()
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Text("공지사항을 불러오는 중입니다...")
+                }
+            }
         }

DetailNoticeViewModel.loadNoticeById()에서 errorMessage 초기화는 올바르게 구현되어 있습니다.

🤖 Prompt for AI Agents
In
`@app/src/main/java/com/konkuk/medicarecall/ui/feature/settings/screen/AnnouncementDetailScreen.kt`
around lines 75 - 122, The when block lacks a fallback for the initial state
(isLoading=false, noticeData=null, errorMessage=null) causing a blank screen;
add a final else branch (or change to if/elseChain) that renders a sensible
fallback UI (e.g., a loading/empty state with a message and CTAButton) and/or
triggers detailViewModel.loadNoticeById(noticeId) so users can retry,
referencing isLoading, noticeData, errorMessage, AnnouncementDetailContent,
CTAButton and detailViewModel.loadNoticeById to locate where to add the new
branch.

@ProtossManse ProtossManse merged commit 5b28c37 into develop Jan 29, 2026
2 checks passed
@ProtossManse ProtossManse deleted the refactor/optimization-navigation-#234 branch January 29, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] 네비게이션 인자 전달 방식 최적화

3 participants