Conversation
…역 bottomnavigation의 visible을 건들 수 있도록 구현
# Conflicts: # core/data/src/main/java/com/example/data/datasource/remote/UserRemoteDataSource.kt
There was a problem hiding this comment.
Pull request overview
이 PR은 자체 QA를 통해 발견된 여러 개선 사항들을 구현합니다. 주요 변경 사항으로는 프로필 이미지 처리 개선, 웹뷰 구현, 마이페이지 삭제 기능, 네비게이션 애니메이션 제거, UI 개선 등이 포함됩니다.
Changes:
- 프로필 이미지 처리를 Uri에서 String으로 변경하고 공통 컴포넌트(DPlayProfileImageArea) 추가
- 설정 및 온보딩 화면에 웹뷰 연결 구현 (약관, 공지사항, 문의 등)
- 마이페이지에서 등록한 곡 삭제 기능 및 상세 페이지 이동 구현
- 네비게이션 애니메이션 제거 및 스플래시 시간 단축 (2초→1초)
- 바텀 네비게이션 컨트롤러 추가 및 탭 로우 UI 개선
- 온보딩 페이지에 이미지 추가
Reviewed changes
Copilot reviewed 31 out of 35 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| feature/splash/SplashViewModel.kt | 스플래시 딜레이를 2초에서 1초로 단축 |
| feature/setting/* | 웹뷰 오픈 기능 추가 (공지사항, 문의, 약관 등) |
| feature/onboarding/* | 프로필 이미지 String 처리, 약관 웹뷰, 알림 권한 업데이트, 네비게이션 애니메이션 제거, 이미지 추가 |
| feature/mypage/* | 삭제 기능 구현, 트랙 클릭 네비게이션, 바텀시트/다이얼로그 추가, 빈 화면 뷰 추가 |
| feature/main/MainActivity.kt | 바텀 네비게이션 컨트롤러 통합, 네비게이션 애니메이션 제거 |
| feature/editprofile/EditProfileScreen.kt | DPlayProfileImageArea 컴포넌트로 리팩토링 |
| feature/detail/DetailScreen.kt | 기본 프로필 이미지 처리 추가 |
| feature/comment/* | 가이드 웹뷰 추가, 등록 후 홈으로 이동 변경 |
| core/ui/controller/BottomNavigationController.kt | 바텀 네비게이션 표시/숨김 컨트롤러 신규 추가 |
| core/designsystem/component/DPlayProfileImageArea.kt | 프로필 이미지 영역 공통 컴포넌트 신규 추가 |
| core/designsystem/res/drawable/base_profile_image.png | 기본 프로필 이미지 리소스 추가 |
| core/domain/model/Writer.kt | profileImg를 nullable로 변경 |
| core/data/* | PatchProfileRequest 추가, 멀티파트 요청 변경, 매퍼 수정 |
| core/common/constant/Url.kt | URL 상수 객체 신규 추가 |
| core/common/type/TermType.kt | 약관 타입에 URL 추가 |
| ), | ||
| exit = | ||
| slideOutVertically( | ||
| targetOffsetY = { 0 }, |
There was a problem hiding this comment.
exit 애니메이션의 targetOffsetY가 0으로 설정되어 있어 바텀시트가 사라질 때 화면 상단으로 이동합니다. 이는 의도한 동작이 아닌 것으로 보입니다. slideOutVertically에서 targetOffsetY는 { it }로 설정하여 아래로 슬라이드되도록 해야 합니다.
| targetOffsetY = { 0 }, | |
| targetOffsetY = { it }, // 바텀시트가 아래로 슬라이드되며 사라지도록 수정 |
| ) | ||
| }, | ||
| ) { padding -> | ||
| val bottomPadding = if (navigator.shouldShowBottomSheet) padding.calculateBottomPadding() else 0.dp |
There was a problem hiding this comment.
bottomPadding 계산 로직이 중복되고 있습니다. navigator.shouldShowBottomSheet 조건이 BottomNavigationBar의 isVisible과 bottomPadding 계산에 모두 사용되는데, BottomNavigationBar가 보이지 않을 때도 padding이 적용될 수 있습니다. bottomNavigationController.bottomNavigationVisible도 함께 고려해야 합니다.
| modifier = | ||
| Modifier | ||
| .clip(CircleShape) | ||
| .border( | ||
| width = 1.dp, | ||
| color = DPlayTheme.colors.gray200, | ||
| shape = CircleShape, | ||
| ), | ||
| contentScale = ContentScale.Crop, | ||
| ) |
There was a problem hiding this comment.
Box에 적용된 modifier (size 포함)가 AsyncImage로 전달되지 않고 있습니다. AsyncImage에 matchParentSize() 또는 fillMaxSize()를 적용하지 않으면 이미지가 Box의 크기를 채우지 못합니다. AsyncImage의 modifier를 Modifier.matchParentSize()로 시작하도록 수정해야 합니다.
| .updateNotificationEnabled(intent.isGranted) | ||
| .onSuccess { | ||
| setSideEffect(OnboardingContract.OnboardingSideEffect.NavigateToHome) | ||
| }.onFailure { |
There was a problem hiding this comment.
알림 권한 설정 업데이트가 실패했을 때(onFailure) 처리 로직이 비어있습니다. 실패해도 홈 화면으로 이동하거나, 에러를 사용자에게 알려야 합니다. 현재는 실패 시 아무 동작도 하지 않아 사용자가 대기 상태에 갇힐 수 있습니다.
| }.onFailure { | |
| }.onFailure { | |
| // 알림 설정 저장이 실패하더라도 사용자 흐름이 막히지 않도록 홈 화면으로 이동 | |
| setSideEffect(OnboardingContract.OnboardingSideEffect.NavigateToHome) |
| // 에러 뷰 | ||
| const val ERROR = "" |
There was a problem hiding this comment.
ERROR 상수가 빈 문자열로 정의되어 있습니다. 빈 문자열을 URL로 사용하면 의도하지 않은 동작이 발생할 수 있습니다. null을 반환하거나 유효한 에러 페이지 URL을 제공하는 것이 좋습니다.
| // 에러 뷰 | |
| const val ERROR = "" | |
| // 에러 뷰 - 빈 문자열 대신 안전한 기본 에러 URL 사용 | |
| const val ERROR = "about:blank" |
| suspend fun patchProfile( | ||
| @Part profileImg: MultipartBody.Part?, | ||
| @Part("nickname") request: String?, | ||
| @Part("changeProfileRequest") request: PatchProfileRequest, |
| ) : MyPageIntent | ||
|
|
||
| data class OnKebabIconClick( | ||
| val musicId: Long, |
There was a problem hiding this comment.
OnKebabIconClick의 파라미터 이름이 musicId로 되어 있지만, 실제로는 postId를 받아야 합니다. OnScrappedTrackClick과 OnRegisteredTrackClick은 postId를 사용하므로 일관성을 위해 musicId를 postId로 변경해야 합니다.
| val musicId: Long, | |
| val postId: Long, |
| Spacer(modifier = Modifier.height(184.dp)) | ||
|
|
||
| Text( | ||
| text = "아직 등록한 곡이 없어요", |
There was a problem hiding this comment.
ScrappedMusicEmptyView의 텍스트가 RegisteredMusicEmptyView와 동일합니다. "아직 스크랩한 곡이 없어요" 또는 유사한 메시지로 변경되어야 합니다.
| text = "아직 등록한 곡이 없어요", | |
| text = "아직 스크랩한 곡이 없어요", |
| updateState { | ||
| copy( | ||
| isDeleteBottomSheetVisible = true, | ||
| selectedPostId = intent.musicId, |
There was a problem hiding this comment.
OnKebabIconClick intent의 파라미터 이름이 musicId로 되어 있지만 실제로는 postId를 전달받아야 합니다. 다른 intent들(OnRegisteredTrackClick, OnScrappedTrackClick)은 postId라는 명확한 이름을 사용하고 있으므로, 일관성을 위해 musicId를 postId로 변경해야 합니다.
| selectedPostId = intent.musicId, | |
| selectedPostId = intent.postId, |
| ) | ||
| } | ||
| }.onFailure { | ||
| Timber.d(t = it, message = "deletePost 실패") |
There was a problem hiding this comment.
삭제가 실패했을 때(onFailure) 사용자에게 에러 메시지를 표시하는 로직이 없습니다. 로그만 남기고 있어 사용자는 삭제가 실패했는지 알 수 없습니다. 에러 스낵바나 토스트를 통해 실패를 알려야 합니다.
| Timber.d(t = it, message = "deletePost 실패") | |
| // 삭제 실패 시 로그만 남기지 말고, UI에 에러를 알려 사용자 경험을 개선한다. | |
| Timber.e(t = it, message = "deletePost 실패") | |
| setSideEffect( | |
| MyPageContract.MyPageSideEffect.ShowErrorToast( | |
| message = "삭제에 실패했어요. 잠시 후 다시 시도해 주세요." | |
| ) | |
| ) |
Related issue 🛠
Work Description ✏️
To Reviewers 📢