feat : AlertScreen 구현#28
Hidden character warning
Conversation
WalkthroughAlert 관련 API와 데이터 모델을 단순화하고 AppliedAlert 관련 엔티티와 UI를 제거했으며, 이미지 처리 API를 Painter에서 ImageRef 기반으로 전환하고 Alert 화면·뷰모델·네비게이션 흐름을 리팩토링했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Screen as AlertScreen
participant VM as AlertViewModel
participant Repo as AlertRepository
participant DS as AlertDataSource
participant Svc as AlertService
participant API as API
User->>Screen: 화면 진입
Screen->>VM: load()
VM->>VM: uiState = Loading
VM->>Repo: getAlerts()
Repo->>DS: getAlerts()
DS->>Svc: getAlerts() 호출
Svc->>API: GET /api/studies/applied
API-->>Svc: AlertResponseDto(studies)
Svc-->>DS: 응답 반환
DS-->>Repo: 응답 반환
Repo->>Repo: DTO → 도메인 매핑
Repo-->>VM: Result<AlertResult>
alt Success
VM->>VM: studies 비었는지 검사
alt 비었음
VM->>VM: uiState = Empty
else
VM->>VM: uiState = Success(AlertResult)
end
else Failure
VM->>VM: Log.e()
VM->>VM: uiState = Failure
end
VM-->>Screen: uiState 업데이트
Screen->>User: 목록 렌더링
User->>Screen: 항목 클릭(studyId)
Screen->>MainNav: onClickAlert(studyId)
MainNav->>User: navigateToStudyDetail(studyId)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code graph analysis (1)feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt (5)
🔇 Additional comments (1)
✏️ Tip: You can disable this entire section by setting 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@data/alert/src/main/java/com/umcspot/spot/alert/mapper/AlertMapper.kt`:
- Around line 9-15: AlertItem.toDomain currently calls
this.applicationId.toLong() and this.studyId.toLong() which can throw
NumberFormatException for empty/invalid/null strings; change the mapper to
safely parse these values (use toLongOrNull on applicationId and studyId),
handle null results (e.g., return a default/fallback, throw a clear
domain-specific exception, or propagate a validation error) and update AlertInfo
construction to use the validated Longs; alternatively, if API spec guarantees
numeric IDs, update the DTO types so applicationId and studyId are Long and
remove string-to-long conversion in AlertItem.toDomain.
In `@domain/alert/src/main/java/com/umcspot/spot/alert/model/AlertResult.kt`:
- Around line 10-15: The AlertInfo data class contains an unused applicationId
field; remove applicationId from AlertInfo and update any mappers and DTOs that
populate it (e.g., AlertMapper) so they no longer map or expect that property,
and update any tests or serialization logic accordingly; if you intend to keep
it for future use instead, add a clear comment above AlertInfo explaining the
planned use and why it is kept, and ensure callers (e.g., places building
AlertInfo and the AlertRow onClick flow) are consistent with the chosen
approach.
In `@feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt`:
- Around line 115-118: The current LazyColumn items call uses key = { it.studyId
} which can collide when a study has multiple alerts; change the key selector to
use the alert's unique identifier (applicationId) instead (i.e., replace key = {
it.studyId } with key = { it.applicationId }) and ensure applicationId is
stable/non-null (fall back to a stable alternative like toString()/hash if
nullable) so each alert item has a unique, stable key.
🧹 Nitpick comments (9)
core/designsystem/src/main/java/com/umcspot/spot/designsystem/shapes/Shapes.kt (4)
128-147:painter타입이 nullable일 필요가 없습니다.
when표현식의 모든 분기에서 non-nullPainter를 반환하므로,Painter?타입과 line 160의 null 체크가 불필요합니다. 이는 dead code로 남게 됩니다.♻️ 제안하는 수정
- val painter: Painter? = when (imageRef) { + val painter: Painter = when (imageRef) { ImageRef.None -> painterResource(fallback) is ImageRef.Name -> { val resId = remember(imageRef.name) { context.resources.getIdentifier( imageRef.name, "drawable", context.packageName ) } if (resId != 0) painterResource(resId) else painterResource(fallback) } is ImageRef.Url -> rememberAsyncImagePainter(model = imageRef.url) is ImageRef.LocalUri -> rememberAsyncImagePainter(model = imageRef.uri) }- if (painter != null) { - Image( - painter = painter, - contentDescription = null, - contentScale = contentScale, - modifier = Modifier - .wrapContentSize() - .padding(padding) - ) - } + Image( + painter = painter, + contentDescription = null, + contentScale = contentScale, + modifier = Modifier + .wrapContentSize() + .padding(padding) + )Also applies to: 160-169
88-88: 중복된screenWidthDp(size)적용외부
Box(line 88)와 내부ShapeImageBox(line 92) 모두에 동일한screenWidthDp(size)가 적용되어 있습니다. 기능적으로는 문제없지만, 내부 컴포넌트에서fillMaxSize()를 사용하면 코드가 더 명확해질 수 있습니다.Also applies to: 92-92
107-107:contentDescription이 null로 하드코딩됨 - 접근성 고려 필요
contentDescription이null로 설정되어 있어 스크린 리더 사용자에게 이미지 정보가 전달되지 않습니다. 접근성(Accessibility)을 위해 이미지 설명을 매개변수로 받는 것을 고려해 주세요.단, 순수 장식용 이미지라면
null이 적절합니다.Also applies to: 163-163
142-146: URL/LocalUri 이미지 로딩 시 placeholder 및 error 처리 권장
rememberAsyncImagePainter를 사용할 때 네트워크 지연이나 로딩 실패 시 사용자 경험을 위해placeholder와error파라미터를 추가하는 것이 좋습니다.♻️ 제안하는 수정
is ImageRef.Url -> - rememberAsyncImagePainter(model = imageRef.url) + rememberAsyncImagePainter( + model = imageRef.url, + placeholder = painterResource(fallback), + error = painterResource(fallback) + ) is ImageRef.LocalUri -> - rememberAsyncImagePainter(model = imageRef.uri) + rememberAsyncImagePainter( + model = imageRef.uri, + placeholder = painterResource(fallback), + error = painterResource(fallback) + )data/alert/src/main/java/com/umcspot/spot/alert/repositoryimpl/AlertRepositoryImpl.kt (1)
13-19: 구현이 적절합니다.DataSource 추상화를 통해 Repository가 Service에 직접 의존하지 않도록 개선되었습니다.
runCatching과onFailure를 사용한 에러 처리 패턴도 적절합니다.다만,
android.util.Log대신 프로젝트 전반에서 사용하는 로깅 추상화(Timber 등)가 있다면 일관성을 위해 해당 라이브러리 사용을 고려해 보세요.data/alert/src/main/java/com/umcspot/spot/alert/dto/response/AlertResponseDto.kt (1)
17-29: ID 필드 타입을 API 스펙에 맞게 조정 권장
applicationId와studyId가 String으로 선언되어 있지만, mapper에서toLong()으로 변환하고 있습니다. API 응답이 숫자 형태라면 DTO에서 직접Long타입으로 선언하는 것이 직렬화 오류를 조기에 감지할 수 있고 mapper에서의 변환 로직을 제거할 수 있습니다.♻️ Long 타입 사용 제안
data class AlertItem( `@SerialName`("applicationId") - val applicationId: String, + val applicationId: Long, `@SerialName`("studyId") - val studyId: String, + val studyId: Long, `@SerialName`("title") val title: String, `@SerialName`("profileImageRef") val profileImageRef: ImageRef, )feature/alert/src/main/java/com/umcspot/spot/alert/AlertViewmodel.kt (1)
23-25: AlertState를 ViewModel 외부로 분리 고려
AlertStatedata class가AlertViewModel내부에 정의되어 있어, 다른 곳에서 참조할 때AlertViewModel.AlertState로 접근해야 합니다. 재사용성과 테스트 용이성을 위해 별도 파일이나 클래스 외부로 분리하는 것을 권장합니다.feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt (2)
86-98: Failure와 Empty 상태의 UI 동일 처리
UiState.Failure와UiState.Empty가 동일한 UI로 표시되어 사용자가 네트워크 오류인지 실제로 알림이 없는 것인지 구분할 수 없습니다. 에러 상태에 대해 별도의 UI나 재시도 버튼을 제공하는 것을 고려해 주세요.
144-148: 고정 크기 사용에 대한 검토 필요
BlankButton에screenWidthDp(326.dp)와screenHeightDp(65.dp)로 고정 크기가 설정되어 있습니다. 부모 컨테이너의 padding과 함께 사용될 때 일부 화면에서 잘림 현상이 발생할 수 있습니다.fillMaxWidth()와wrapContentHeight()또는IntrinsicSize사용을 검토해 주세요.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
core/designsystem/src/main/java/com/umcspot/spot/designsystem/component/study/EnrollStudyItem.ktcore/designsystem/src/main/java/com/umcspot/spot/designsystem/shapes/Shapes.ktcore/designsystem/src/main/res/drawable/announce.xmlcore/model/src/main/java/com/umcspot/spot/model/Global.ktdata/alert/src/main/java/com/umcspot/spot/alert/datasource/AlertDataSource.ktdata/alert/src/main/java/com/umcspot/spot/alert/datasourceimpl/AlertDataSourceImpl.ktdata/alert/src/main/java/com/umcspot/spot/alert/dto/response/AlertResponseDto.ktdata/alert/src/main/java/com/umcspot/spot/alert/mapper/AlertMapper.ktdata/alert/src/main/java/com/umcspot/spot/alert/repositoryimpl/AlertRepositoryImpl.ktdata/alert/src/main/java/com/umcspot/spot/alert/service/AlertService.ktdomain/alert/src/main/java/com/umcspot/spot/alert/model/AlertResult.ktdomain/alert/src/main/java/com/umcspot/spot/alert/repository/AlertRepository.ktfeature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.ktfeature/alert/src/main/java/com/umcspot/spot/alert/AlertViewmodel.ktfeature/alert/src/main/java/com/umcspot/spot/alert/navigation/AlertNavigation.ktfeature/main/src/main/java/com/umcspot/spot/main/MainNavHost.kt
💤 Files with no reviewable changes (5)
- data/alert/src/main/java/com/umcspot/spot/alert/datasource/AlertDataSource.kt
- core/model/src/main/java/com/umcspot/spot/model/Global.kt
- core/designsystem/src/main/java/com/umcspot/spot/designsystem/component/study/EnrollStudyItem.kt
- data/alert/src/main/java/com/umcspot/spot/alert/datasourceimpl/AlertDataSourceImpl.kt
- domain/alert/src/main/java/com/umcspot/spot/alert/repository/AlertRepository.kt
🧰 Additional context used
🧬 Code graph analysis (3)
feature/alert/src/main/java/com/umcspot/spot/alert/navigation/AlertNavigation.kt (1)
feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt (1)
AlertScreen(38-101)
core/designsystem/src/main/java/com/umcspot/spot/designsystem/shapes/Shapes.kt (1)
core/ui/src/main/java/com/umcspot/spot/ui/extension/DimensionExt.kt (1)
screenWidthDp(18-23)
feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt (4)
core/ui/src/main/java/com/umcspot/spot/ui/extension/DimensionExt.kt (2)
screenWidthDp(18-23)screenHeightDp(11-16)core/designsystem/src/main/java/com/umcspot/spot/designsystem/component/empty/EmptyAlert.kt (1)
EmptyAlert(34-71)core/designsystem/src/main/java/com/umcspot/spot/designsystem/component/button/ImageButton.kt (1)
BlankButton(112-151)core/designsystem/src/main/java/com/umcspot/spot/designsystem/shapes/Shapes.kt (1)
ShapeImageBox(113-172)
🔇 Additional comments (7)
core/designsystem/src/main/res/drawable/announce.xml (1)
1-12: LGTM!벡터 드로어블이 48dp에서 16dp로 적절하게 리사이징되었습니다. viewport 크기와 pathData가 새로운 좌표계에 맞게 올바르게 재계산되었으며, fillColor도 그대로 유지되어 있습니다.
core/designsystem/src/main/java/com/umcspot/spot/designsystem/shapes/Shapes.kt (2)
16-16: LGTM!
ImageRef기반 이미지 처리를 위한 필요한 import들이 적절하게 추가되었습니다. Coil의rememberAsyncImagePainter와screenWidthDp확장 함수 사용이 적절합니다.Also applies to: 24-24, 28-28, 31-32
75-110:ImageRef패턴 도입 승인
ShapeImageWithBadge에서ImageRef기반 이미지 처리로 전환한 것은 좋은 설계입니다. 다양한 이미지 소스(None, Name, Url, LocalUri)를 유연하게 처리할 수 있게 되었습니다.data/alert/src/main/java/com/umcspot/spot/alert/service/AlertService.kt (1)
7-11: LGTM!API 엔드포인트가
/api/studies/applied로 업데이트되었고, 인터페이스가 깔끔하게 정의되어 있습니다. AppliedAlert 관련 메서드 제거와 함께 단순화된 구조가 적절합니다.feature/alert/src/main/java/com/umcspot/spot/alert/navigation/AlertNavigation.kt (1)
17-29: LGTM!
onClickAlert: (Long) -> Unit콜백이 적절하게 추가되었고, AlertScreen으로 올바르게 전달됩니다. 기존onRegisterScrollToTop패턴과 일관된 구조입니다.feature/main/src/main/java/com/umcspot/spot/main/MainNavHost.kt (1)
143-147: LGTM!알림 클릭 시 스터디 상세 화면으로 이동하는 네비게이션 연결이 적절합니다.
registerStudyGraph의navigateToStudyDetail호출과 동일한 패턴을 따르고 있습니다.feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt (1)
38-44: LGTM!
contentPadding과onClickAlert콜백을 통한 외부 연동이 잘 설계되어 있습니다.rememberSaveable을 사용한 리스트 상태 보존도 적절합니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| fun AlertItem.toDomain() : AlertInfo = | ||
| AlertInfo ( | ||
| id = this.id, | ||
| kind = this.kind, | ||
| applicationId = this.applicationId.toLong(), | ||
| studyId = this.studyId.toLong(), | ||
| title = this.title, | ||
| studyImageRes = this.studyImageRes, | ||
| subtitle = this.subtitle, | ||
| isRead = this.isRead | ||
| studyImageRes = this.profileImageRef, | ||
| ) |
There was a problem hiding this comment.
toLong() 호출 시 NumberFormatException 발생 가능
applicationId와 studyId가 String 타입인데 toLong()을 직접 호출하면, API에서 유효하지 않은 값(빈 문자열, null, 숫자가 아닌 문자열 등)이 반환될 경우 런타임 크래시가 발생합니다.
🛠️ 안전한 변환을 위한 수정 제안
fun AlertItem.toDomain() : AlertInfo =
AlertInfo (
- applicationId = this.applicationId.toLong(),
- studyId = this.studyId.toLong(),
+ applicationId = this.applicationId.toLongOrNull() ?: 0L,
+ studyId = this.studyId.toLongOrNull() ?: 0L,
title = this.title,
studyImageRes = this.profileImageRef,
)또는 DTO에서 applicationId와 studyId를 처음부터 Long 타입으로 선언하는 것이 더 적절할 수 있습니다. API 응답 스펙을 확인해 주세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fun AlertItem.toDomain() : AlertInfo = | |
| AlertInfo ( | |
| id = this.id, | |
| kind = this.kind, | |
| applicationId = this.applicationId.toLong(), | |
| studyId = this.studyId.toLong(), | |
| title = this.title, | |
| studyImageRes = this.studyImageRes, | |
| subtitle = this.subtitle, | |
| isRead = this.isRead | |
| studyImageRes = this.profileImageRef, | |
| ) | |
| fun AlertItem.toDomain() : AlertInfo = | |
| AlertInfo ( | |
| applicationId = this.applicationId.toLongOrNull() ?: 0L, | |
| studyId = this.studyId.toLongOrNull() ?: 0L, | |
| title = this.title, | |
| studyImageRes = this.profileImageRef, | |
| ) |
🤖 Prompt for AI Agents
In `@data/alert/src/main/java/com/umcspot/spot/alert/mapper/AlertMapper.kt` around
lines 9 - 15, AlertItem.toDomain currently calls this.applicationId.toLong() and
this.studyId.toLong() which can throw NumberFormatException for
empty/invalid/null strings; change the mapper to safely parse these values (use
toLongOrNull on applicationId and studyId), handle null results (e.g., return a
default/fallback, throw a clear domain-specific exception, or propagate a
validation error) and update AlertInfo construction to use the validated Longs;
alternatively, if API spec guarantees numeric IDs, update the DTO types so
applicationId and studyId are Long and remove string-to-long conversion in
AlertItem.toDomain.
| data class AlertInfo( | ||
| val id: Int, | ||
| val kind: AlertKind, | ||
| val applicationId: Long, | ||
| val studyId: Long, | ||
| val title: String, | ||
| val subtitle: String = "", | ||
| val studyImageRes: ImageRef = ImageRef.None, | ||
| val isRead: Boolean = false | ||
| ) { | ||
| companion object { | ||
| fun dummyAlert(id: Int, total: Int): AlertInfo { | ||
| val kind = AlertKind.values()[(id - 1) % AlertKind.values().size] | ||
|
|
||
| return when (kind) { | ||
| AlertKind.POPULAR_POST -> | ||
| AlertInfo( | ||
| id = id, | ||
| kind = kind, | ||
| title = "실시간 인기 글", | ||
| subtitle = "Sample Post Title", | ||
| studyImageRes = ImageRef.Name("ic_fire"), | ||
| isRead = false | ||
| ) | ||
|
|
||
| AlertKind.STUDY_NOTICE -> | ||
| AlertInfo( | ||
| id = id, | ||
| kind = kind, | ||
| title = "내 스터디 '공지' 업데이트", | ||
| subtitle = "\"Sample Study\"의 새로운 공지", | ||
| studyImageRes = ImageRef.Name("sample"), | ||
| isRead = false | ||
| ) | ||
|
|
||
| AlertKind.STUDY_SCHEDULE -> | ||
| AlertInfo( | ||
| id = id, | ||
| kind = kind, | ||
| title = "내 스터디 '새 일정' 등록", | ||
| subtitle = "\"Sample Study\"의 새로운 일정", | ||
| studyImageRes = ImageRef.Name("ic_study_default"), | ||
| isRead = false | ||
| ) | ||
|
|
||
| AlertKind.TODO_DONE -> | ||
| AlertInfo( | ||
| id = id, | ||
| kind = kind, | ||
| title = "‘사용자님’의 “Sample Todolist” 할 일 완료!", | ||
| subtitle = "\"Sample Study\"의 ‘사용자님’", | ||
| studyImageRes = ImageRef.Name("ic_check_filled"), | ||
| isRead = false | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| val studyImageRes: ImageRef, | ||
| ) No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for applicationId usage across the codebase
echo "=== Searching for applicationId references ==="
rg "applicationId" --type=kt -C2Repository: SPOTeam/Android-V2
Length of output: 152
🏁 Script executed:
#!/bin/bash
# Also check how AlertInfo is instantiated
echo "=== Searching for AlertInfo instantiation ==="
rg "AlertInfo\(" --type=kt -C3Repository: SPOTeam/Android-V2
Length of output: 151
🏁 Script executed:
#!/bin/bash
# Check the AlertResult.kt file to see the full context
echo "=== Full content of AlertResult.kt ==="
find . -name "AlertResult.kt" -type f | head -5Repository: SPOTeam/Android-V2
Length of output: 173
🏁 Script executed:
#!/bin/bash
# Read the AlertResult.kt file
cat -n ./domain/alert/src/main/java/com/umcspot/spot/alert/model/AlertResult.ktRepository: SPOTeam/Android-V2
Length of output: 464
🏁 Script executed:
#!/bin/bash
# Search for applicationId without file type restriction
rg "applicationId" -C2Repository: SPOTeam/Android-V2
Length of output: 1661
🏁 Script executed:
#!/bin/bash
# Search for AlertInfo instantiation/usage
rg "AlertInfo" -C2Repository: SPOTeam/Android-V2
Length of output: 3858
🏁 Script executed:
#!/bin/bash
# Check where applicationId is actually used (not just declared/imported)
# Look in AlertScreen and AlertViewmodel for actual usage
echo "=== AlertScreen.kt content ==="
rg -A 30 "fun AlertRow" feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.ktRepository: SPOTeam/Android-V2
Length of output: 1115
🏁 Script executed:
#!/bin/bash
# Check AlertViewmodel for applicationId usage
echo "=== AlertViewmodel.kt content ==="
cat feature/alert/src/main/java/com/umcspot/spot/alert/AlertViewmodel.ktRepository: SPOTeam/Android-V2
Length of output: 1761
🏁 Script executed:
#!/bin/bash
# Search for where onClickAlert is called and what parameter is passed
echo "=== Search for onClickAlert usage ==="
rg "onClickAlert\|onClick\(" feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.kt -C3Repository: SPOTeam/Android-V2
Length of output: 99
🏁 Script executed:
#!/bin/bash
# Check the full AlertScreen.kt to see navigation parameters
echo "=== Full AlertScreen.kt ==="
cat feature/alert/src/main/java/com/umcspot/spot/alert/AlertScreen.ktRepository: SPOTeam/Android-V2
Length of output: 5950
🏁 Script executed:
#!/bin/bash
# Search for where AlertScreen is composed and how onClickAlert is handled
echo "=== Search for AlertScreen composition ==="
rg "AlertScreen\(" -C5Repository: SPOTeam/Android-V2
Length of output: 2381
🏁 Script executed:
#!/bin/bash
# Search for any other usage of applicationId in the navigation or elsewhere
echo "=== Search for applicationId usage beyond definitions ==="
rg "\.applicationId" -C3Repository: SPOTeam/Android-V2
Length of output: 833
applicationId 필드는 사용되지 않고 있습니다.
코드를 검토한 결과, applicationId는 AlertMapper에서 API 응답값으로 매핑되지만 실제 애플리케이션 로직 어디에서도 사용되지 않습니다. AlertRow의 네비게이션에서는 오직 studyId만 전달되며(onClick(data.studyId)), 다른 곳에서도 applicationId를 참조하지 않습니다.
불필요한 필드는 제거하거나, 향후 사용 계획이 있다면 명확하게 주석으로 문서화하는 것을 권장합니다.
🤖 Prompt for AI Agents
In `@domain/alert/src/main/java/com/umcspot/spot/alert/model/AlertResult.kt`
around lines 10 - 15, The AlertInfo data class contains an unused applicationId
field; remove applicationId from AlertInfo and update any mappers and DTOs that
populate it (e.g., AlertMapper) so they no longer map or expect that property,
and update any tests or serialization logic accordingly; if you intend to keep
it for future use instead, add a clear comment above AlertInfo explaining the
planned use and why it is kept, and ensure callers (e.g., places building
AlertInfo and the AlertRow onClick flow) are consistent with the chosen
approach.
| .onFailure { e -> | ||
| Log.e("AlertViewModel", "loadAlert error", e) | ||
| // _uiState.update { state -> state.copy(alerts = UiState.Failure(e.message ?: e.toString())) } | ||
| } |
There was a problem hiding this comment.
실패 시 UI 상태 업데이트 누락
onFailure 블록에서 로그만 출력하고 UI 상태를 업데이트하지 않아, API 호출 실패 시 사용자가 무한 로딩 상태에 머물게 됩니다.
🛠️ 실패 상태 처리 활성화
.onFailure { e ->
Log.e("AlertViewModel", "loadAlert error", e)
-// _uiState.update { state -> state.copy(alerts = UiState.Failure(e.message ?: e.toString())) }
+ _uiState.update { state -> state.copy(alerts = UiState.Failure(e.message ?: e.toString())) }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .onFailure { e -> | |
| Log.e("AlertViewModel", "loadAlert error", e) | |
| // _uiState.update { state -> state.copy(alerts = UiState.Failure(e.message ?: e.toString())) } | |
| } | |
| .onFailure { e -> | |
| Log.e("AlertViewModel", "loadAlert error", e) | |
| _uiState.update { state -> state.copy(alerts = UiState.Failure(e.message ?: e.toString())) } | |
| } |
Related issue 🛠
Work Description 📝
Screenshot 📸
Uncompleted Tasks 😅
PR Point 📌
트러블 슈팅 💥
Summary by CodeRabbit
새로운 기능
개선사항
변경
✏️ Tip: You can customize this high-level summary in your review settings.