Skip to content

[feat] #178 select-album 모듈 구현 및 upload-album 전환#185

Open
ikseong00 wants to merge 7 commits intodevelopfrom
feat/#178-select-album
Open

[feat] #178 select-album 모듈 구현 및 upload-album 전환#185
ikseong00 wants to merge 7 commits intodevelopfrom
feat/#178-select-album

Conversation

@ikseong00
Copy link
Copy Markdown
Contributor

@ikseong00 ikseong00 commented Apr 9, 2026

🔗 관련 이슈

📙 작업 설명

  • feature/select-album 모듈(api/impl) 생성 및 의존성 설정
  • SelectAlbumScreen 구현: 앨범 목록 조회, 앨범 생성, 앨범 선택 후 결과 전달
  • upload-album 제거 후 select-album으로 전환
    • SelectAlbum은 앨범 선택만 담당, 실제 업로드 usecase는 결과를 수신하는 MainViewModel에서 처리
  • 앨범 선택 후 업로드 성공 시 Archive 화면 새로고침 누락 수정

🧪 테스트 내역 (선택)

  • 주요 기능 정상 동작 확인
  • 기기에서 동작 확인
  • 기존 기능 영향 없음

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

기능 미리보기
앨범 선택 후 업로드
Screen_recording_20260410_015713.mp4

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

  • SelectAlbum은 photoCount: Int만 받아 상단 TopBar에 표시 (${photoCount}장 업로드)
  • 업로드 결과(QR/갤러리 URI)는 SelectAlbum을 거치지 않고 MainViewModel state에 유지되다가, AlbumSelected result 수신 후 처리
  • 앨범 있이 업로드 시: NavigateToAlbumDetail + RefreshArchive 둘 다 post → AlbumDetail에서 뒤로가기 시 Archive 자동 갱신

Summary by CodeRabbit

새로운 기능

  • 앨범 선택 화면이 추가되었습니다. 사용자는 이제 사진 업로드 시 대상 앨범을 선택할 수 있습니다.
  • 새 앨범 생성 기능이 선택 화면에서 지원됩니다.

개선사항

  • 사진 업로드 워크플로우가 개선되었습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

Walkthrough

앱에서 UploadAlbum 기능(impl)을 제거하고 새 SelectAlbum 기능 모듈(api/impl)을 추가했습니다. Main 화면의 네비게이션·업로드 흐름과 ViewModel이 SelectAlbum 결과 기반으로 재연결되었고 관련 NavKey·EntryProvider·UI·ViewModel이 추가/삭제되었습니다.

Changes

Cohort / File(s) Summary
Gradle 설정
app/build.gradle.kts, settings.gradle.kts, feature/select-album/api/build.gradle.kts, feature/select-album/impl/build.gradle.kts
앱 및 settings에 feature:select-album:api/impl 추가; 신규 모듈용 Gradle 스크립트 추가 및 app 의존성에 select-album 모듈 포함.
Main 화면 연결
app/src/main/java/com/neki/android/app/MainActivity.kt, app/src/main/java/com/neki/android/app/main/MainScreen.kt, app/src/main/java/com/neki/android/app/main/MainViewModel.kt, app/src/main/java/com/neki/android/app/main/MainContract.kt
UploadAlbum 관련 네비게이션 콜백/사이드이펙트 제거 및 SelectAlbum/AlbumDetail 내비게이션으로 전환; AlbumSelected 인텐트 추가; 업로드 함수 시그니처 및 흐름을 앨범 옵션을 받도록 변경.
PhotoUpload API 변경
feature/photo-upload/api/src/main/java/com/neki/android/feature/photo_upload/api/PhotoUploadNavKey.kt
PhotoUploadNavKey.UploadAlbum 및 관련 MainNavigator.navigateToUploadAlbum 확장 함수 제거; QRScan 관련만 유지.
UploadAlbum 기능 제거 (impl)
feature/photo-upload/impl/src/main/java/.../album/* (예: UploadAlbumContract.kt, UploadAlbumScreen.kt, UploadAlbumViewModel.kt, component/UploadAlbumTopBar.kt)
UploadAlbum 관련 컨트랙트, 스크린, ViewModel, 컴포넌트, entry provider 등록 등 해당 기능 전체 삭제.
SelectAlbum API 추가
feature/select-album/api/src/main/java/com/neki/android/feature/select_album/api/SelectAlbumNavKey.kt, .../SelectAlbumResult.kt
SelectAlbumNavKey.SelectAlbumMainNavigator.navigateToSelectAlbum(...) 추가; SelectAlbumResult 데이터 클래스 추가.
SelectAlbum 구현 추가
feature/select-album/impl/src/main/java/... (SelectAlbumContract.kt, SelectAlbumScreen.kt, SelectAlbumViewModel.kt, SelectAlbumTopBar.kt, navigation/SelectAlbumEntryProvider.kt)
선택 화면의 상태/인텐트/사이드이펙트 정의, Compose UI, Hilt-assisted ViewModel, EntryProvider 등록 등 SelectAlbum 기능 전체 구현 추가.
DI/EntryProvider 변경
feature/photo-upload/impl/.../di/PhotoUploadEntryProvider.kt, feature/select-album/impl/.../SelectAlbumEntryProvider.kt
PhotoUpload의 UploadAlbum 엔트리 등록 제거; SelectAlbum 엔트리 제공 모듈 추가.
기타 영향 파일
app/build.gradle.kts
앱 모듈 의존성에 SelectAlbum API/impl 추가(빌드 설정 변경).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant Main as Main Screen
    participant MainVM as Main ViewModel
    participant Navigator as MainNavigator
    participant Select as SelectAlbum Screen
    participant SelectVM as SelectAlbum ViewModel
    participant Repo as Repository
    participant Upload as Upload UseCase
    participant Detail as AlbumDetail Screen

    User->>Main: 앨범으로 업로드 클릭
    Main->>MainVM: ClickUploadWithAlbum
    MainVM->>Navigator: NavigateToSelectAlbum(photoCount)
    Navigator->>Select: open SelectAlbum (with photoCount)
    Select->>SelectVM: EnterSelectAlbumScreen
    SelectVM->>Repo: load favorite + folders
    Repo-->>SelectVM: album list
    User->>Select: 선택 후 확인
    Select->>SelectVM: ClickConfirmButton
    SelectVM->>Navigator: SendResult(selectedAlbums) + goBack
    Navigator->>Main: return SelectAlbumResult
    Main->>MainVM: AlbumSelected(intent)
    MainVM->>Upload: uploadSingleImage/uploadMultipleImages(..., album)
    Upload->>Repo: upload (folderId = album?.id)
    Repo-->>Upload: success
    MainVM->>Navigator: NavigateToAlbumDetail(album.id, album.title)
    Navigator->>Detail: navigateToAlbumDetail(id, title)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 깡충, 새 길 열렸네 —
옛 업로드는 내려놓고,
SelectAlbum 창이 반짝 떠요.
사진 골라 찰칵, 폴더로 쏙!
토끼가 즐거이 발을 구르네. 🎉🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 요약하고 있으며, select-album 모듈 구현 및 upload-album 전환이라는 핵심 내용을 잘 반영하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 필수 섹션(관련 이슈, 작업 설명, 테스트 내역)을 모두 포함하고 있으며, 상세한 구현 내용과 리뷰 포인트를 제시하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #178의 요구사항(SelectAlbum 화면 구현, 앨범 목록 조회, 앨범 생성, 선택 결과 반환, 아키텍처 분리)을 충족합니다.
Out of Scope Changes check ✅ Passed PR의 모든 변경사항은 select-album 모듈 구현 및 upload-album 전환이라는 명시된 목표와 직접 관련되어 있으며, 범위를 벗어난 변경은 없습니다.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#178-select-album

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
Copy Markdown

@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

🧹 Nitpick comments (1)
feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt (1)

125-148: 앨범 생성 중 로딩 표시 부재

handleAddAlbum에서 네트워크 요청 중 로딩 상태를 설정하지 않습니다. 사용자가 "추가하기" 버튼을 여러 번 클릭하면 중복 요청이 발생할 수 있습니다.

🔧 로딩 상태 추가 제안
 private fun handleAddAlbum(
     albumName: String,
     reduce: (SelectAlbumState.() -> SelectAlbumState) -> Unit,
     postSideEffect: (SelectAlbumSideEffect) -> Unit,
 ) {
     viewModelScope.launch {
+        reduce { copy(isLoading = true) }
         folderRepository.createFolder(name = albumName)
             .onSuccess {
                 fetchFolders(reduce)
                 reduce {
                     copy(
+                        isLoading = false,
                         isShowAddAlbumBottomSheet = false,
                         albumNameTextState = TextFieldState(),
                     )
                 }
                 postSideEffect(SelectAlbumSideEffect.ShowToastMessage("새로운 앨범을 추가했어요"))
             }
             .onFailure { e ->
                 Timber.e(e)
-                reduce { copy(isShowAddAlbumBottomSheet = false, albumNameTextState = TextFieldState()) }
+                reduce { copy(isLoading = false, isShowAddAlbumBottomSheet = false, albumNameTextState = TextFieldState()) }
                 postSideEffect(SelectAlbumSideEffect.ShowToastMessage("앨범 추가에 실패했어요"))
             }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`
around lines 125 - 148, The add-album flow in handleAddAlbum does not set a
loading flag so duplicate taps can trigger multiple requests; before launching
folderRepository.createFolder inside viewModelScope.launch, call reduce to set a
new SelectAlbumState flag (e.g., isAddingAlbum or isLoadingAlbum = true) and
disable the add button in the UI based on that flag, then after onSuccess and
onFailure ensure you reset that flag to false (alongside the existing
isShowAddAlbumBottomSheet and albumNameTextState updates); optionally, guard at
the top of handleAddAlbum by checking the state flag and returning early if
already loading to fully prevent concurrent requests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@feature/select-album/api/src/main/java/com/neki/android/feature/select_album/api/SelectAlbumNavKey.kt`:
- Line 7: Remove the unnecessary consecutive blank line in SelectAlbumNavKey.kt
that triggers Detekt's NoConsecutiveBlankLines rule (the extra empty line around
line 7); open the file containing the SelectAlbumNavKey declaration and delete
the extra blank line so there is only a single empty line between
sections/statements, then run Detekt/CI to confirm the warning is resolved.

In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`:
- Around line 69-73: SelectAlbumViewModel currently passes the raw album name
from the intent handler to handleAddAlbum without defensive
trimming/empty-checking; update the ClickAddAlbumConfirmButton handling in
SelectAlbumViewModel so that before calling handleAddAlbum you call .trim() on
state.albumNameTextState.text and skip/return early (or do not call
handleAddAlbum) if the trimmed string is empty, matching the pattern used in
ArchiveMainViewModel.handleAddAlbum; ensure reduce and postSideEffect are
preserved when calling handleAddAlbum.

---

Nitpick comments:
In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`:
- Around line 125-148: The add-album flow in handleAddAlbum does not set a
loading flag so duplicate taps can trigger multiple requests; before launching
folderRepository.createFolder inside viewModelScope.launch, call reduce to set a
new SelectAlbumState flag (e.g., isAddingAlbum or isLoadingAlbum = true) and
disable the add button in the UI based on that flag, then after onSuccess and
onFailure ensure you reset that flag to false (alongside the existing
isShowAddAlbumBottomSheet and albumNameTextState updates); optionally, guard at
the top of handleAddAlbum by checking the state flag and returning early if
already loading to fully prevent concurrent requests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e6db1ab7-926d-427f-a80a-f2f6d956babe

📥 Commits

Reviewing files that changed from the base of the PR and between 4d23ae7 and 59853f9.

📒 Files selected for processing (21)
  • app/build.gradle.kts
  • app/src/main/java/com/neki/android/app/MainActivity.kt
  • app/src/main/java/com/neki/android/app/main/MainContract.kt
  • app/src/main/java/com/neki/android/app/main/MainScreen.kt
  • app/src/main/java/com/neki/android/app/main/MainViewModel.kt
  • feature/photo-upload/api/src/main/java/com/neki/android/feature/photo_upload/api/PhotoUploadNavKey.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/UploadAlbumContract.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/UploadAlbumScreen.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/UploadAlbumViewModel.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/component/UploadAlbumTopBar.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/di/PhotoUploadEntryProvider.kt
  • feature/select-album/api/build.gradle.kts
  • feature/select-album/api/src/main/java/com/neki/android/feature/select_album/api/SelectAlbumNavKey.kt
  • feature/select-album/api/src/main/java/com/neki/android/feature/select_album/api/SelectAlbumResult.kt
  • feature/select-album/impl/build.gradle.kts
  • feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumContract.kt
  • feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumScreen.kt
  • feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumTopBar.kt
  • feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt
  • feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/navigation/SelectAlbumEntryProvider.kt
  • settings.gradle.kts
💤 Files with no reviewable changes (6)
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/di/PhotoUploadEntryProvider.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/component/UploadAlbumTopBar.kt
  • feature/photo-upload/api/src/main/java/com/neki/android/feature/photo_upload/api/PhotoUploadNavKey.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/UploadAlbumContract.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/UploadAlbumScreen.kt
  • feature/photo-upload/impl/src/main/java/com/neki/android/feature/photo_upload/impl/album/UploadAlbumViewModel.kt

Copy link
Copy Markdown
Member

@Ojongseok Ojongseok left a comment

Choose a reason for hiding this comment

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

고생하셨습니닷

Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt (1)

65-69: ⚠️ Potential issue | 🟡 Minor

공백 앨범명이 생성 요청으로 전달될 수 있습니다.

Line 65-67에서 입력값을 그대로 넘겨 " " 같은 값이 요청으로 전달될 수 있습니다. ViewModel에서 trim() 후 빈 값이면 조기 반환해 주세요. (이 이슈는 이전 리뷰에서도 이미 지적된 항목입니다.)

제안 수정안
-            SelectAlbumIntent.ClickAddAlbumConfirmButton -> handleAddAlbum(
-                albumName = state.albumNameTextState.text.toString(),
-                reduce = reduce,
-                postSideEffect = postSideEffect,
-            )
+            SelectAlbumIntent.ClickAddAlbumConfirmButton -> {
+                val trimmedAlbumName = state.albumNameTextState.text.toString().trim()
+                if (trimmedAlbumName.isEmpty()) return
+                handleAddAlbum(
+                    albumName = trimmedAlbumName,
+                    reduce = reduce,
+                    postSideEffect = postSideEffect,
+                )
+            }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`
around lines 65 - 69, When handling
SelectAlbumIntent.ClickAddAlbumConfirmButton, sanitize the input before calling
handleAddAlbum: retrieve state.albumNameTextState.text, call trim() and if the
resulting string is empty return early (do not call handleAddAlbum or post side
effects); otherwise pass the trimmed string as albumName into handleAddAlbum so
no whitespace-only names are sent to the request.
🧹 Nitpick comments (1)
feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt (1)

130-141: 성공/실패 분기의 바텀시트 초기화 로직이 중복됩니다.

Line 130-135와 Line 140에서 동일 상태 초기화가 반복됩니다. 헬퍼로 추출하면 추후 상태 변경 시 누락 위험을 줄일 수 있습니다.

리팩터링 예시
+    private fun resetAddAlbumSheetState(
+        reduce: (SelectAlbumState.() -> SelectAlbumState) -> Unit,
+    ) {
+        reduce {
+            copy(
+                isShowAddAlbumBottomSheet = false,
+                albumNameTextState = TextFieldState(),
+            )
+        }
+    }
+
     private fun handleAddAlbum(
         albumName: String,
         reduce: (SelectAlbumState.() -> SelectAlbumState) -> Unit,
         postSideEffect: (SelectAlbumSideEffect) -> Unit,
     ) {
         viewModelScope.launch {
             folderRepository.createFolder(name = albumName)
                 .onSuccess {
                     fetchFolders(reduce)
-                    reduce {
-                        copy(
-                            isShowAddAlbumBottomSheet = false,
-                            albumNameTextState = TextFieldState(),
-                        )
-                    }
+                    resetAddAlbumSheetState(reduce)
                     postSideEffect(SelectAlbumSideEffect.ShowToastMessage("새로운 앨범을 추가했어요"))
                 }
                 .onFailure { e ->
                     Timber.e(e)
-                    reduce { copy(isShowAddAlbumBottomSheet = false, albumNameTextState = TextFieldState()) }
+                    resetAddAlbumSheetState(reduce)
                     postSideEffect(SelectAlbumSideEffect.ShowToastMessage("앨범 추가에 실패했어요"))
                 }
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`
around lines 130 - 141, The reduce logic that resets isShowAddAlbumBottomSheet
and albumNameTextState is duplicated in both the success and failure branches of
the add-album flow; extract a single helper (e.g., a private method
resetAddAlbumUiState or an inline function resetAddAlbumState) and call it from
both the success path (after reduce { ... } currently) and the onFailure path
before posting side effects, updating uses of reduce, SelectAlbumSideEffect,
albumNameTextState, and isShowAddAlbumBottomSheet so the UI-reset behavior is
centralized and only maintained in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`:
- Around line 65-69: When handling SelectAlbumIntent.ClickAddAlbumConfirmButton,
sanitize the input before calling handleAddAlbum: retrieve
state.albumNameTextState.text, call trim() and if the resulting string is empty
return early (do not call handleAddAlbum or post side effects); otherwise pass
the trimmed string as albumName into handleAddAlbum so no whitespace-only names
are sent to the request.

---

Nitpick comments:
In
`@feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt`:
- Around line 130-141: The reduce logic that resets isShowAddAlbumBottomSheet
and albumNameTextState is duplicated in both the success and failure branches of
the add-album flow; extract a single helper (e.g., a private method
resetAddAlbumUiState or an inline function resetAddAlbumState) and call it from
both the success path (after reduce { ... } currently) and the onFailure path
before posting side effects, updating uses of reduce, SelectAlbumSideEffect,
albumNameTextState, and isShowAddAlbumBottomSheet so the UI-reset behavior is
centralized and only maintained in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 90a557b9-6173-48e5-8338-ed285d72aa0a

📥 Commits

Reviewing files that changed from the base of the PR and between f1d12d8 and 45d5db3.

📒 Files selected for processing (1)
  • feature/select-album/impl/src/main/java/com/neki/android/feature/select_album/impl/SelectAlbumViewModel.kt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] SelectAlbum 화면 구현

2 participants