Skip to content

Conversation

@PIYUJIN
Copy link
Member

@PIYUJIN PIYUJIN commented Jul 9, 2025

🔎 What type of PR is this? (check all applicable)

  • Feature
  • Bug Fix
  • Setting
  • Refactor
  • Optimization
  • Documentation Update
  • Others: ...

📝 Changes

매장 관리 화면 수정사항 및 기능 구현

🐥 What need this change?



📷 Screenshots, Recordings (optional)

Summary by CodeRabbit

  • 신규 기능

    • 기본/공통 주류 이미지(소주, 맥주, 생맥주, 하이볼, 기본 이미지) 추가 및 관리 기능이 도입되었습니다.
    • 생맥주, 하이볼 주류를 버튼으로 간편하게 추가할 수 있습니다.
    • 커스텀 토스트(알림) UI가 추가되어 주요 안내 메시지가 버튼 위에 표시됩니다.
  • UI/스타일 개선

    • 주류 추가/관리 화면 레이아웃이 개선되고, 버튼 및 리스트 디자인이 향상되었습니다.
    • 필수 입력 항목에 별표(*) 표시가 추가되어 입력 가이드가 명확해졌습니다.
    • 새로운 배경, 테두리, 아이콘 등 다양한 드로어블 리소스가 추가되었습니다.
  • 버그 수정 및 개선

    • 주류 이름의 중복 체크가 더 엄격하게 동작합니다.
    • 이미지 삭제 및 인덱스 관리 로직이 개선되었습니다.
    • 저장 버튼 활성화 조건이 완화되어, 이미지/설명/인스타그램 중 하나만 입력해도 저장이 가능합니다.
  • 기타

    • 픽셀 변환 등 유틸리티 기능이 추가되었습니다.

@PIYUJIN PIYUJIN self-assigned this Jul 9, 2025
@PIYUJIN PIYUJIN added the ✨ feat 신규 기능 구현 작업 label Jul 9, 2025
@PIYUJIN PIYUJIN linked an issue Jul 9, 2025 that may be closed by this pull request
3 tasks
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 9, 2025

Walkthrough

이번 변경에서는 공통 이미지 데이터 클래스를 도입하고, 기본 토스트 UI 유틸리티 및 픽셀 변환 확장 함수를 추가했습니다. 주류 관리 화면의 기본 주류(생맥주, 하이볼 등) 처리와 인덱스 관리, 중복 체크 로직이 개선되었으며, 레이아웃 전반에 걸쳐 버튼, 섹션, 마진, 스타일이 조정되었습니다. 신규 벡터 아이콘과 배경 drawable, 토스트 레이아웃이 추가되었습니다.

Changes

파일/경로 요약 변경 요약
.../api/request/image/StoreImageRequest.kt CommonImageData 데이터 클래스 추가 (image, type, description 포함)
.../ui/BasicToast.kt, .../util/MainUtil.kt 커스텀 토스트 유틸리티 오브젝트 및 Int.toPx() 확장 함수 추가
.../ui/home/adapter/AvailableDrinkAdapter.kt TextView 텍스트 설정 방식을 setText() 메서드로 변경
.../ui/store/StoreAvailableDrinksBottomSheetFragment.kt 버튼 활성화 조건에서 이미지 업로드 여부 제거
.../ui/store/StoreDetailAvailableDrinksFragment.kt 공통 주류 이미지 분리(CommonImageData), 생맥주/하이볼 추가, 인덱스 및 중복 체크 로직 개선
.../ui/store/StoreDetailInfoFragment.kt 인스타그램 미입력 시 토스트 안내 추가, 저장 버튼 활성화 조건 완화
.../ui/store/StoreDetailInfoMainFragment.kt 버튼 클릭 시 홈으로 직접 이동, UI 체크 및 버튼 매핑 로직 재배치, 완료 조건 변경
.../viewModel/StoreViewModel.kt editStoreInfo 성공 처리에서 분기 제거, 단순화
.../res/drawable/background_*.xml, ic_check.xml, ic_edit.xml 신규 배경 drawable 및 벡터 아이콘 추가
.../res/layout/fragment_store_detail_available_drinks.xml 기본 주류 버튼 추가, 패딩/마진/버튼 레이아웃 조정
.../res/layout/fragment_store_detail_info.xml 매장 소개 필수 표시(*) 제거
.../res/layout/fragment_store_detail_info_main.xml 섹션명/순서/ID/필수표시(*) 등 레이아웃 대폭 리팩토링
.../res/layout/row_available_drink.xml 배경 이미지, 이름 레이아웃, 편집 버튼 등 UI 구성요소 추가 및 스타일 변경
.../res/layout/toast_basic.xml 커스텀 토스트 레이아웃 추가
.../res/values/styles.xml 상단만 라운드(16dp) 스타일 추가

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant StoreDetailAvailableDrinksFragment
    participant UI
    participant Adapter

    User->>StoreDetailAvailableDrinksFragment: 기본 주류(예: 생맥주) 추가 버튼 클릭
    StoreDetailAvailableDrinksFragment->>StoreDetailAvailableDrinksFragment: CommonImageData 생성 및 인덱스 관리
    StoreDetailAvailableDrinksFragment->>Adapter: 이미지 리스트 갱신
    Adapter->>UI: RecyclerView 갱신

    User->>StoreDetailAvailableDrinksFragment: 주류 삭제 버튼 클릭
    StoreDetailAvailableDrinksFragment->>StoreDetailAvailableDrinksFragment: 해당 주류 인덱스/리스트 갱신
    StoreDetailAvailableDrinksFragment->>Adapter: 이미지 리스트 갱신
    Adapter->>UI: RecyclerView 갱신
Loading
sequenceDiagram
    participant User
    participant BasicToast
    participant UI

    User->>UI: 저장/입력 등 특정 액션
    UI->>BasicToast: showBasicToast(context, message, icon, anchorView)
    BasicToast->>UI: 커스텀 토스트 팝업 표시
    Note over BasicToast: 2초 후 자동 dismiss
Loading

Poem

🐰
새로운 주류, 생맥주와 하이볼
버튼도 토스트도 한층 더 고올~
그림자 둥글게, 체크마크 반짝
중복 없는 관리, 인덱스도 착착
토끼는 기뻐서 깡총깡총 춤을 춰요!
🍻✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae2c2fc and 6446bcc.

📒 Files selected for processing (1)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoMainFragment.kt (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoMainFragment.kt
✨ 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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

🧹 Nitpick comments (13)
app/src/main/res/drawable/background_gray3_radius16_top.xml (1)

6-8: 상단 라운드만 필요한 상황인지 다시 확인 필요

하단 모서리에 radius 가 없는 디자인이 확정된 사항인지 확인해 주세요. 동일 drawable 을 재사용하다가 하단도 라운드가 필요한 컴포넌트가 나오면 새 파일이 또 늘어날 수 있습니다. 재사용성을 고려해 radius="16dp" + android:bottomLeftRadius="0dp" 식으로 파라미터화된 단일 리소스를 두고 필요 시 style 로 분기하는 방법도 있습니다.

app/src/main/res/drawable/ic_check.xml (1)

6-15: 벡터 path fillType 미지정 시 렌더링 이슈 가능

일부 기기(Android < 5.0)에서 겹치는 path 가 있을 때 android:fillType="evenOdd"/nonZero 미지정 시 알파 블렌딩 문제를 겪은 사례가 있습니다. 원형-배경 + 체크 path 조합이라 크게 문제는 없겠지만, 호환성을 위해 각 path 에 android:fillType="nonZero" 를 명시하는 것을 추천드립니다.

app/src/main/res/layout/toast_basic.xml (1)

1-35: 토스트 레이아웃 구조 양호

토스트 레이아웃이 깔끔하게 구성되어 있습니다. 하지만 접근성 향상을 위해 개선을 제안합니다.

접근성 개선을 위한 수정 제안:

         <ImageView
             android:id="@+id/imageView_tooltip"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
             android:layout_marginEnd="10dp"
+            android:contentDescription="@string/check_icon"
             android:src="@drawable/ic_check" />
app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt (3)

25-27: 하드코딩된 마진 값을 상수로 추출하는 것을 고려해보세요.

20dp 마진과 같은 하드코딩된 값들은 상수로 추출하거나 리소스에서 가져오는 것이 유지보수에 더 좋습니다.

+    companion object {
+        private const val HORIZONTAL_MARGIN_DP = 20
+        private const val VERTICAL_OFFSET_DP = 8
+        private const val DISMISS_DELAY_MS = 2000L
+    }
+    
    fun showBasicToast(context: Context, message: String, icon: Int, anchorView: View) {
        val inflater = LayoutInflater.from(context)
        val binding: ToastBasicBinding =
            DataBindingUtil.inflate(inflater, R.layout.toast_basic, null, false)

        binding.run {
            textViewTooltip.text = message
            imageViewTooltip.setImageResource(icon)
        }

        val screenWidth = Resources.getSystem().displayMetrics.widthPixels
-        val marginPx = 20.toPx()
+        val marginPx = HORIZONTAL_MARGIN_DP.toPx()
        val popupWidth = screenWidth - marginPx * 2

42-42: 오프셋 계산에서 하드코딩된 값을 상수로 추출하세요.

yOffset 계산에서 사용되는 8.toPx() 값도 상수로 추출하는 것이 좋습니다.

-            val yOffset = -(anchorView.height + popupHeight + 8.toPx())
+            val yOffset = -(anchorView.height + popupHeight + VERTICAL_OFFSET_DP.toPx())

46-48: 자동 해제 지연 시간도 상수로 추출하세요.

2초 지연 시간도 상수로 추출하여 일관성을 유지하세요.

            binding.root.postDelayed({
                popupWindow.dismiss()
-            }, 2000)
+            }, DISMISS_DELAY_MS)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoMainFragment.kt (2)

109-109: null 안전성 검사를 개선하세요.

availableDrinkImageUrls?.size != 0 대신 !availableDrinkImageUrls.isNullOrEmpty()를 사용하는 것이 더 안전하고 가독성이 좋습니다.

-            if(storeInfo?.availableDrinkImageUrls?.size != 0) {
+            if(!storeInfo?.availableDrinkImageUrls.isNullOrEmpty()) {

150-150: 일관성을 위해 동일한 null 안전성 검사를 적용하세요.

메뉴 이미지 URL 검사에도 동일한 개선사항을 적용하세요.

-            if(storeInfo?.menuImageUrls?.size != 0) {
+            if(!storeInfo?.menuImageUrls.isNullOrEmpty()) {
app/src/main/res/layout/row_available_drink.xml (1)

64-73: 편집 버튼의 접근성을 고려하세요.

편집 버튼에 contentDescription을 추가하여 접근성을 향상시키는 것을 고려해보세요.

        <ImageView
            android:id="@+id/button_edit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_marginStart="4dp"
            android:layout_gravity="center"
+            android:contentDescription="@string/edit_drink_name"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/ic_edit" />
app/src/main/res/layout/fragment_store_detail_info_main.xml (1)

77-87: 필수 필드 표시자 ID 명명 규칙을 일관성 있게 적용하세요.

첫 번째 필드의 필수 표시자 ID가 textView_info_title1_essential인데, 두 번째 필드는 textView_info_title5_essential입니다. 숫자 순서를 일관성 있게 맞춰주세요.

                <TextView
-                    android:id="@+id/textView_info_title5_essential"
+                    android:id="@+id/textView_info_title2_essential"
                    style="@style/SubTitle2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="5dp"
                    android:text="*"
                    android:textColor="@color/red"
                    app:layout_constraintStart_toEndOf="@+id/textView_info_title2"
                    app:layout_constraintTop_toTopOf="@+id/textView_info_title2"
                    app:layout_constraintBottom_toBottomOf="@+id/textView_info_title2"/>
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (3)

77-80: 조건문 명확성 개선 필요

else if (imageFile == null) 조건은 name != null인 경우를 명시적으로 체크하는 것이 좋습니다.

-} else if (imageFile== null) {
+} else if (imageFile == null && name != null) {

137-183: 하드코딩된 URL을 상수로 분리 권장

이미지 URL들이 하드코딩되어 있습니다. 유지보수성을 위해 companion object에 상수로 정의하는 것이 좋습니다.

companion object {
    private const val SOJU_IMAGE_URL = "공통주류/20250507034147-40441a71-23e6-4166-8965-ce331aab5998-soju"
    private const val BEER_IMAGE_URL = "공통주류/20250507034229-20802afc-98f4-44ce-aec7-12a559a96668-beer"
    private const val DRAFT_BEER_IMAGE_URL = "공통주류/20250617200637-a0444443-5965-418e-9802-19cca40de2c8-draft"
    private const val HIGHBALL_IMAGE_URL = "공통주류/20250617200742-72659ec0-e6ea-498e-baaf-197f4997f833-highball"
    private const val BASIC_IMAGE_URL = "공통주류/20250618155356-8e22ebc7-72a0-4c19-b5e5-7a2c4c880c68-basic"
}

245-283: 복잡한 인덱스 관리 로직 개선 필요

이미지 삭제 시 인덱스를 조정하는 로직이 복잡합니다. 별도의 메서드로 분리하여 가독성을 높이는 것이 좋습니다.

private fun adjustIndicesAfterRemoval(removedIndex: Int) {
    if (removedIndex < newSojuIndex) newSojuIndex--
    if (removedIndex < newBeerIndex) newBeerIndex--
    if (removedIndex < newDraftBeerIndex) newDraftBeerIndex--
    if (removedIndex < newHighballIndex) newHighballIndex--
}

private fun resetDrinkIndex(drinkName: String) {
    when (drinkName) {
        "소주" -> newSojuIndex = 0
        "병맥주" -> newBeerIndex = 0
        "생맥주" -> newDraftBeerIndex = 0
        "하이볼" -> newHighballIndex = 0
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ce833d and 88fa2a4.

⛔ Files ignored due to path filters (5)
  • app/src/main/res/drawable/img_basic.png is excluded by !**/*.png
  • app/src/main/res/drawable/img_beer.png is excluded by !**/*.png
  • app/src/main/res/drawable/img_draft_beer.png is excluded by !**/*.png
  • app/src/main/res/drawable/img_highball.png is excluded by !**/*.png
  • app/src/main/res/drawable/img_soju.png is excluded by !**/*.png
📒 Files selected for processing (22)
  • app/src/main/java/com/project/drinkly_admin/api/request/image/StoreImageRequest.kt (1 hunks)
  • app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt (1 hunks)
  • app/src/main/java/com/project/drinkly_admin/ui/home/adapter/AvailableDrinkAdapter.kt (1 hunks)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreAvailableDrinksBottomSheetFragment.kt (1 hunks)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (8 hunks)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoFragment.kt (3 hunks)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoMainFragment.kt (3 hunks)
  • app/src/main/java/com/project/drinkly_admin/util/MainUtil.kt (1 hunks)
  • app/src/main/java/com/project/drinkly_admin/viewModel/StoreViewModel.kt (1 hunks)
  • app/src/main/res/drawable/background_gray3_radius16_top.xml (1 hunks)
  • app/src/main/res/drawable/background_white_radius10_stroke_primary30.xml (1 hunks)
  • app/src/main/res/drawable/background_white_radius10_stroke_yellow.xml (1 hunks)
  • app/src/main/res/drawable/background_white_radius12.xml (1 hunks)
  • app/src/main/res/drawable/background_white_radius12_bottom.xml (1 hunks)
  • app/src/main/res/drawable/ic_check.xml (1 hunks)
  • app/src/main/res/drawable/ic_edit.xml (1 hunks)
  • app/src/main/res/layout/fragment_store_detail_available_drinks.xml (7 hunks)
  • app/src/main/res/layout/fragment_store_detail_info.xml (0 hunks)
  • app/src/main/res/layout/fragment_store_detail_info_main.xml (7 hunks)
  • app/src/main/res/layout/row_available_drink.xml (1 hunks)
  • app/src/main/res/layout/toast_basic.xml (1 hunks)
  • app/src/main/res/values/styles.xml (1 hunks)
💤 Files with no reviewable changes (1)
  • app/src/main/res/layout/fragment_store_detail_info.xml
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (1)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreMenuFragment.kt (1)
  • checkComplete (212-220)
🔇 Additional comments (29)
app/src/main/res/drawable/background_white_radius12.xml (1)

4-6: LGTM – 기본형 흰색 배경 drawable 추가
특이사항 없습니다.

app/src/main/res/drawable/ic_edit.xml (1)

1-16: 벡터 드로어블이 올바르게 구현되었습니다.

편집 아이콘이 적절한 크기(17x16dp)와 일관된 색상 체계(#71788C)로 잘 정의되어 있습니다. XML 구조도 Android 벡터 드로어블 표준을 준수하고 있습니다.

app/src/main/java/com/project/drinkly_admin/viewModel/StoreViewModel.kt (1)

101-103: 네비게이션 흐름이 적절히 유지됩니다.

popBackStack() 호출로 이전에 있던 HomeFragment로 복귀하므로, 기존에 StoreDetailInfoMainFragment에서 직접 replace(..., HomeFragment()) 하던 로직과 동일한 동작을 보장합니다.

  • StoreViewModel.kt (101–103행): activity.supportFragmentManager.popBackStack()
  • StoreDetailInfoMainFragment.kt (buttonNext 클릭 리스너): replace(R.id.fragmentContainerView_main, HomeFragment())
app/src/main/res/drawable/background_white_radius12_bottom.xml (1)

1-9: 하단 모서리만 둥근 배경 드로어블이 올바르게 구현되었습니다.

흰색 배경에 하단 좌우 모서리만 12dp 반경으로 둥글게 처리하는 드로어블이 적절하게 정의되어 있습니다. 모달 하단이나 섹션 끝부분 등에서 유용하게 사용될 수 있습니다.

app/src/main/res/drawable/background_white_radius10_stroke_yellow.xml (1)

1-11: 노란색 테두리가 있는 흰색 배경 드로어블이 올바르게 구현되었습니다.

흰색 배경에 1dp 노란색 테두리와 10dp 모서리 반경을 가진 드로어블이 적절하게 정의되어 있습니다. 버튼이나 강조 요소에 사용하기에 적합한 스타일입니다.

app/src/main/res/drawable/background_white_radius10_stroke_primary30.xml (1)

1-11: primary_30 색상 테두리가 있는 흰색 배경 드로어블이 올바르게 구현되었습니다.

흰색 배경에 1dp primary_30 색상 테두리와 10dp 모서리 반경을 가진 드로어블이 적절하게 정의되어 있습니다. 앱의 기본 색상 팔레트를 사용하여 일관된 디자인을 제공합니다.

app/src/main/java/com/project/drinkly_admin/ui/store/StoreAvailableDrinksBottomSheetFragment.kt (1)

148-156: 이미지 업로드 요구사항 완화로 UX 개선됨

checkComplete() 함수에서 isImageUpload 조건을 제거하여 사용자가 이미지 없이도 음료를 추가할 수 있도록 개선되었습니다. 이는 사용자 경험을 향상시키는 좋은 변경사항입니다.

app/src/main/java/com/project/drinkly_admin/ui/home/adapter/AvailableDrinkAdapter.kt (1)

48-48: 텍스트 설정 방식 개선

프로퍼티 세터 대신 setText() 메서드를 사용하여 더 명시적인 코드가 되었습니다.

app/src/main/res/values/styles.xml (1)

153-159: 새로운 라운드 스타일 추가

상단 모서리만 둥글게 처리하는 RoundSector16Top 스타일이 추가되었습니다. 기존 스타일과 일관된 네이밍 및 구조를 따르고 있어 좋습니다.

app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoFragment.kt (3)

23-23: BasicToast 유틸리티 추가

새로운 BasicToast 유틸리티를 import하여 사용자 알림 기능을 향상시켰습니다.


172-174: 사용자 안내 토스트 추가

Instagram URL이 비어있을 때 대표 이미지 등록을 안내하는 토스트를 추가했습니다. 사용자 경험을 향상시키는 좋은 기능입니다.


210-210: 저장 버튼 활성화 조건 개선

저장 버튼 활성화 조건이 OR 조건으로 변경되어 더 유연해졌습니다. 이미지, 설명, 또는 Instagram URL 중 하나라도 입력되면 저장할 수 있도록 개선되었습니다.

app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailInfoMainFragment.kt (1)

84-87: HomeFragment로 직접 이동하기 전, 서브 프래그먼트에서 editStoreInfo 호출이 유지되어 데이터 일관성이 보장됩니다.

StoreDetailInfoFragment, StoreAvailableDaysFragment, StoreOpenTimeFragment 등에서 viewModel.editStoreInfo(...)를 정상 호출한 뒤 MainFragment에서 HomeFragment로 전환되므로, 의도된 동작이며 데이터 일관성에 문제가 없습니다.

app/src/main/res/layout/fragment_store_detail_available_drinks.xml (4)

32-32: 패딩 값 변경으로 인한 UI 일관성을 확인하세요.

패딩이 20dp에서 15dp로 변경되었습니다. 이 변경이 전체 UI 일관성에 영향을 주지 않는지 확인해주세요.


130-168: 새로운 주류 버튼 레이아웃이 잘 구성되었습니다.

생맥주와 하이볼 버튼이 추가되면서 UI가 더 완성도 있게 보입니다. 버튼 스타일과 색상도 일관성 있게 적용되었습니다.


104-127: 버튼 너비를 match_parent로 변경한 것이 좋습니다.

기존 wrap_content에서 match_parent로 변경하여 버튼들이 균등하게 배치되도록 한 것은 좋은 개선입니다.


173-173: RecyclerView 높이를 wrap_content로 변경한 것을 확인하세요.

RecyclerView의 높이가 wrap_content로 변경되었습니다. 이것이 성능에 영향을 주지 않는지, 특히 많은 아이템이 있을 때 스크롤 성능에 문제가 없는지 확인해주세요.

app/src/main/res/layout/row_available_drink.xml (3)

4-6: 루트 레이아웃 너비를 wrap_content로 변경한 것을 확인하세요.

루트 ConstraintLayout의 너비가 match_parent에서 wrap_content로 변경되었습니다. 이 변경이 RecyclerView에서 아이템 표시에 영향을 주지 않는지 확인해주세요.


9-18: 배경 오버레이 추가로 시각적 개선이 이루어졌습니다.

ShapeableImageView를 사용하여 배경 오버레이를 추가한 것은 좋은 접근입니다. 둥근 모서리 스타일이 일관성 있게 적용되었습니다.


43-75: 드링크 이름 영역 구조 개선이 잘 되었습니다.

LinearLayout을 사용하여 드링크 이름과 편집 버튼을 함께 배치한 것은 좋은 구조적 개선입니다. 편집 버튼이 초기에 숨겨져 있어 필요할 때만 표시할 수 있도록 준비되어 있습니다.

app/src/main/res/layout/fragment_store_detail_info_main.xml (4)

56-97: 필수 필드 표시자 추가로 UX가 개선되었습니다.

빨간 별표(*) 표시자를 추가하여 필수 필드를 명확히 표시한 것은 좋은 UX 개선입니다. 사용자가 어떤 필드가 필수인지 쉽게 알 수 있습니다.


56-255: 섹션 순서 재배열이 논리적으로 잘 구성되었습니다.

매장 정보 섹션들의 순서를 재배열하여 사용자 경험을 개선한 것은 좋은 변경입니다. 멤버십 제공 주류 → 이용 가능 요일 → 영업시간 → 매장 정보 → 메뉴판 순으로 진행하는 것이 자연스럽습니다.


204-209: 매장 정보 섹션에서 필수 표시자가 누락되었습니다.

다른 섹션들에는 필수 표시자(*)가 있지만 매장 정보 섹션에는 없습니다. 이것이 의도된 것인지 확인해주세요. 만약 매장 정보도 필수 필드라면 표시자를 추가해야 합니다.


239-244: 메뉴판 섹션에서도 필수 표시자가 누락되었습니다.

메뉴판 섹션에도 필수 표시자가 없습니다. 일관성을 위해 필수 필드인지 확인하고 필요하다면 표시자를 추가해주세요.

app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (5)

16-16: 새로운 데이터 타입 추가 확인

CommonImageData 타입이 새롭게 추가되었습니다. 기본 주류 이미지를 관리하는 용도로 보입니다.


43-43: 기본 주류 관리를 위한 새로운 변수 추가

기본 주류 이미지를 별도로 관리하기 위한 리스트와 생맥주, 하이볼 인덱스가 추가되었습니다.

Also applies to: 49-50


96-96: 기본 주류 추가 로직 개선

소주와 병맥주 추가 시 CommonImageData를 사용하도록 변경되었으며, "맥주"가 "병맥주"로 명확히 구분되었습니다.

Also applies to: 103-106


112-131: 생맥주와 하이볼 추가 기능 구현

새로운 주류 타입인 생맥주와 하이볼 추가 기능이 기존 패턴과 일관성 있게 구현되었습니다.


371-371: 중복 체크 로직 개선

contains에서 정확한 일치(==)로 변경되어 더 엄격한 중복 체크가 가능해졌습니다.

Also applies to: 383-383

Comment on lines 14 to +22
data class ImageData(
val image: Any,
val description: String
)

data class CommonImageData(
val image: Any,
val type: String,
val description: String
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

ImageData vs CommonImageData 중복 – 모델 정리 필요

두 데이터 클래스가 image·description 을 공유하고 CommonImageData 에만 type 필드가 추가되었습니다. 모델 중복은 유지보수 비용을 키우므로 다음을 고려해 주세요.

  1. type 을 nullable 로 두고 단일 ImageData 로 통합
  2. sealed class/인터페이스 로 공통 필드를 추상화
  3. UI 전용 모델은 ui.model 패키지로 이동하여 API 요청용 DTO 와 분리

또한 image: Any 는 타입 안정성이 없습니다. Uri | Int 등 실제 사용 타입을 sealed 로 좁히는 편이 안전합니다.

빠른 의견 부탁드립니다. 필요하면 리팩터 제안 PR 드리겠습니다.


🏁 Script executed:

#!/bin/bash
# 프로젝트 내에서 ImageData와 CommonImageData의 사용처 검색
rg -n "ImageData" -n .
rg -n "CommonImageData" -n .

Length of output: 6327


중복된 ImageData 모델 통합 및 타입 안전성 확보 필요

공통 필드(image, description)를 갖는 ImageData와 CommonImageData가 중복되어 유지보수 비용이 상승하고 있습니다. 아래 항목을 참고해 리팩터링을 권장합니다.

  • 앱 API DTO (app/src/main/java/com/project/drinkly_admin/api/request/image/StoreImageRequest.kt)
    ImageDataCommonImageData를 단일 ImageData(image, type?, description) 또는 sealed class/인터페이스로 추상화
    image: AnyImageSource(File/Uri/String 등) 같은 sealed class로 구체화
  • UI 계층 모델 분리
    • StoreDetailAvailableDrinksFragment.kt, AvailableDrinkAdapter.kt 등에서 API DTO가 아닌 UI 전용 모델(ui.model 패키지) 사용

예시 diff:

--- a/app/src/main/java/com/project/drinkly_admin/api/request/image/StoreImageRequest.kt
-data class ImageData(
-    val image: Any,
-    val description: String
-)
-
-data class CommonImageData(
-    val image: Any,
-    val type: String,
-    val description: String
-)
+data class ImageData(
+    val image: ImageSource,
+    val type: String? = null,
+    val description: String
+)

ImageSource sealed class 정의 및 UI-DTO 분리를 통해 명확한 계층 구조를 갖추면 유지보수가 용이해집니다.

🤖 Prompt for AI Agents
In
app/src/main/java/com/project/drinkly_admin/api/request/image/StoreImageRequest.kt
around lines 14 to 22, the ImageData and CommonImageData classes have
overlapping fields causing redundancy and maintenance overhead. Refactor by
merging these into a single ImageData class with an optional type field or use a
sealed class/interface abstraction. Replace the generic image: Any type with a
sealed class ImageSource representing specific image types like File, Uri, or
String to improve type safety. Additionally, separate UI models from API DTOs by
creating dedicated UI model classes in a ui.model package for use in UI
components like StoreDetailAvailableDrinksFragment.kt and
AvailableDrinkAdapter.kt.

Copy link
Contributor

@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

🔭 Outside diff range comments (1)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (1)

1-405: 전반적인 아키텍처 개선을 고려해보세요.

새로운 공통 음료 기능이 잘 구현되었지만, 코드 복잡성이 크게 증가했습니다. 다음과 같은 개선을 제안합니다:

  1. 인덱스 관리 클래스 도입: 현재 여러 인덱스 변수들을 하나의 클래스로 관리
  2. 메서드 분리: 큰 메서드들을 작은 단위로 분할
  3. 상태 관리 개선: 음료 추가/제거 상태를 더 체계적으로 관리
data class DrinkIndexManager(
    var soju: Int = 0,
    var beer: Int = 0,
    var draftBeer: Int = 0,
    var highball: Int = 0
) {
    fun adjustForRemoval(removedIndex: Int) { /* 인덱스 조정 로직 */ }
    fun adjustForInsertion(insertedIndex: Int) { /* 인덱스 조정 로직 */ }
}
🧹 Nitpick comments (1)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (1)

51-51: 새로운 변수들이 적절히 추가되었습니다.

다만 인덱스 변수들이 증가하고 있어 향후 리팩토링을 고려해보세요. 인덱스 관리를 위한 별도 클래스나 데이터 구조를 도입하면 가독성과 유지보수성이 향상될 수 있습니다.

Also applies to: 57-58

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b52f9b2 and b64d33e.

📒 Files selected for processing (1)
  • app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (9 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (1)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreMenuFragment.kt (1)
  • checkComplete (212-220)
🔇 Additional comments (4)
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (4)

35-41: 공통 이미지 URL 상수 정의가 잘 구성되어 있습니다.

중앙집중식으로 URL을 관리할 수 있어 유지보수성이 향상됩니다.


85-87: 버튼 클릭 로직이 잘 구현되어 있습니다.

공통 이미지와 커스텀 이미지를 모두 처리하는 로직이 적절합니다. 다만 type 문자열("soju", "beer", "draft-beer", "highball")이 저장 로직의 when 문과 일치하는지 확인이 필요합니다.

Also applies to: 104-104, 114-114, 120-139


145-189: 공통 이미지 저장 로직이 체계적으로 구현되어 있습니다.

각 타입별로 적절한 URL과 설명이 매핑되어 있고, 모든 케이스가 커버되어 있습니다.


378-378: 중복 체크 로직 개선이 적절합니다.

부분 문자열 매칭에서 정확한 일치 검사로 변경하여 "맥주"와 "생맥주" 같은 유사한 이름의 음료들을 구분할 수 있게 되었습니다.

Also applies to: 390-390

Comment on lines 250 to 294
override fun onItemClick(position: Int) {
val targetImage = images?.get(position)

if(images?.get(position)?.image is String) {
var imageId = previousAvailableDrinkImages?.find { it.imageUrl == images?.get(position)?.image }?.imageId
if (targetImage?.image is String) {
val imageId = previousAvailableDrinkImages?.find { it.imageUrl == targetImage.image && it.description == targetImage.description }?.imageId
if (imageId != null) {
removedAvailableDrinkImages?.add(imageId)
}
} else if(images?.get(position)?.image is File) {
(images?.get(position))?.let { file ->
if((newAvailableDrinkImages?.indexOf(file) ?: 0) < newSojuIndex) {
newSojuIndex -= 1
}
if((newAvailableDrinkImages?.indexOf(file) ?: 0) < newBeerIndex) {
newBeerIndex -= 1

} else if (targetImage?.image is File) {
val file = targetImage.image as File

val indexInNew = newAvailableDrinkImages?.indexOfFirst {
it.image == file && it.description == targetImage.description
} ?: -1

if (indexInNew >= 0) {
// 인덱스 조정
if (indexInNew < newSojuIndex) newSojuIndex--
if (indexInNew < newBeerIndex) newBeerIndex--
if (indexInNew < newDraftBeerIndex) newDraftBeerIndex--
if (indexInNew < newHighballIndex) newHighballIndex--

newAvailableDrinkImages?.removeAt(indexInNew)
} else {
val indexInCommon = newCommonAvailableDrinkImages?.indexOfFirst {
it.image == file && it.description == targetImage.description
} ?: -1

if (indexInCommon >= 0) {
newCommonAvailableDrinkImages?.removeAt(indexInCommon)

when (targetImage.description) {
"소주" -> newSojuIndex = 0
"병맥주" -> newBeerIndex = 0
"생맥주" -> newDraftBeerIndex = 0
"하이볼" -> newHighballIndex = 0
}
}
newAvailableDrinkImages?.remove(file)
}
}
println(removedAvailableDrinkImages)
images?.removeAt(position)

images?.removeAt(position)
checkComplete()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

아이템 제거 로직의 복잡성을 개선해보세요.

현재 로직은 정확하게 동작하지만 가독성과 유지보수성이 떨어집니다. 다음과 같은 개선을 제안합니다:

private fun handleImageRemoval(position: Int) {
    val targetImage = images?.get(position) ?: return
    
    when (val image = targetImage.image) {
        is String -> handleExistingImageRemoval(image, targetImage.description)
        is File -> handleNewImageRemoval(image, targetImage.description)
    }
    
    images?.removeAt(position)
    checkComplete()
}

별도 메서드로 분리하면 각 케이스별 처리가 명확해집니다.

🤖 Prompt for AI Agents
In
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt
between lines 250 and 294, the onItemClick method has complex logic for removing
items that reduces readability and maintainability. Refactor by extracting the
removal logic into separate helper methods, such as handleExistingImageRemoval
and handleNewImageRemoval, and call these from a new method like
handleImageRemoval that handles the image removal based on the image type. This
separation will clarify each case and simplify the main click handler.

Comment on lines +318 to +354
newCommonAvailableDrinkImages?.forEach { imageData ->
val insertIndex = when (imageData.description) {
"소주" -> newSojuIndex
"병맥주" -> newBeerIndex
"생맥주" -> newDraftBeerIndex
"하이볼" -> newHighballIndex
else -> {
// description에 해당하는 항목을 newAvailableDrinkImages에서 찾아 index 추정
newAvailableDrinkImages?.indexOfFirst { it.description == imageData.description }
?.takeIf { it >= 0 } ?: mappedNewImageUrls.size
}
}

// ⚠️ 맥주 삽입 시 소주 이후일 경우 인덱스 +1 보정 필요
newBeerIndex = if (newSojuIndex <= newBeerIndex) newBeerIndex + 1 else newBeerIndex
}
val imageUrl = when (imageData.type) {
"soju" -> SOJU_IMAGE_URL
"beer" -> BEER_IMAGE_URL
"draft-beer" -> DRAFT_IMAGE_URL
"highball" -> HIGHBALL_IMAGE_URL
"basic" -> BASIC_IMAGE_URL
else -> BASIC_IMAGE_URL
}

val clampedIndex = insertIndex.coerceIn(0, mappedNewImageUrls.size)

// 맥주가 추가되어 있는 경우
if (newCommonAvailableDrinkImages?.any { it.description == "맥주" } == true) {
mappedNewImageUrls.add(
newBeerIndex,
clampedIndex,
NewImageUrl(
imageUrl = "공통주류/20250502162032-b7a26511-55a9-4811-92a2-1ff564a34449-beer",
description = "맥주"
imageUrl = imageUrl,
description = imageData.description
)
)
}

if (clampedIndex <= newSojuIndex) newSojuIndex++
if (clampedIndex <= newBeerIndex) newBeerIndex++
if (clampedIndex <= newDraftBeerIndex) newDraftBeerIndex++
if (clampedIndex <= newHighballIndex) newHighballIndex++
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

복잡한 삽입 로직에 대한 면밀한 검토가 필요합니다.

현재 로직은 매우 복잡하여 버그 발생 가능성이 높습니다. 특히 다음 부분들이 우려됩니다:

  1. 인덱스 계산 로직 (라인 319-329)
  2. 삽입 후 인덱스 조정 로직 (라인 350-354)

다음 테스트 케이스들을 확인해보세요:

  • 여러 공통 음료를 동시에 추가할 때
  • 커스텀 음료와 공통 음료가 섞여있을 때
  • 중간 위치의 음료를 제거한 후 새로운 음료를 추가할 때

별도의 인덱스 관리 클래스 도입을 강력히 권장합니다.


복잡한 삽입 로직 리팩터링 필요

  • 대상 파일: app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt (라인 318–354)
  • 핵심 문제:
    1. 인덱스 계산 로직(319–329)
    2. 삽입 후 인덱스 조정 로직(350–354)
      위 두 부분의 결합으로 가독성 저하 및 엣지 케이스 버그 위험이 큽니다.

제안 사항:

  • “공통 음료 다중 추가”, “커스텀·공통 혼합”, “중간 위치 삭제 후 추가” 등 주요 시나리오에 대한 단위 테스트 작성
  • 독립된 인덱스 관리 클래스를 도입해 삽입 위치 결정과 인덱스 업데이트를 분리·단순화
🤖 Prompt for AI Agents
In
app/src/main/java/com/project/drinkly_admin/ui/store/StoreDetailAvailableDrinksFragment.kt
between lines 318 and 354, the current code combines index calculation and index
adjustment logic for inserting new drink images, which reduces readability and
risks edge case bugs. To fix this, refactor by extracting the index calculation
into a separate method or class responsible solely for determining insert
positions, and create an independent index management class to handle updating
the various category indices after insertion. Additionally, write unit tests
covering key scenarios like multiple common drink additions, mixed custom and
common inserts, and deletions followed by insertions to ensure correctness and
maintainability.

PIYUJIN and others added 2 commits July 14, 2025 00:01
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@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: 0

♻️ Duplicate comments (1)
app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt (1)

46-54: 이전 리뷰 코멘트의 메모리 누수 방지 로직이 잘 적용되었습니다.

OnAttachStateChangeListener를 추가하여 뷰가 detach될 때 PopupWindow를 명시적으로 해제하는 로직이 구현되어 메모리 누수를 방지합니다.

🧹 Nitpick comments (1)
app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt (1)

48-48: 정적 분석 경고: 빈 함수 블록을 정리하세요.

onViewAttachedToWindow 메서드가 비어있어 정적 분석 경고가 발생합니다. 인터페이스 구현상 필요하지만 로직이 없다면 주석으로 의도를 명시하는 것을 고려해보세요.

-                override fun onViewAttachedToWindow(v: View) {}
+                override fun onViewAttachedToWindow(v: View) {
+                    // PopupWindow 생성 후 attach되는 경우는 별도 처리 불필요
+                }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8326740 and ae2c2fc.

📒 Files selected for processing (1)
  • app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt (1 hunks)
🧰 Additional context used
🪛 detekt (1.23.8)
app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt

[warning] 48-48: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🔇 Additional comments (5)
app/src/main/java/com/project/drinkly_admin/ui/BasicToast.kt (5)

14-14: 싱글톤 객체 패턴 적용이 적절합니다.

토스트 유틸리티를 object로 구현하여 메모리 효율성과 접근성을 보장했습니다.


15-23: 데이터 바인딩을 활용한 깔끔한 UI 구성입니다.

LayoutInflater와 DataBindingUtil을 사용하여 레이아웃을 안전하게 인플레이션하고, binding.run 스코프 함수로 코드를 간결하게 작성했습니다.


25-33: 화면 크기 기반 동적 레이아웃 계산이 우수합니다.

시스템 디스플레이 메트릭을 활용하여 마진을 고려한 팝업 너비를 계산하고, 적절한 PopupWindow 설정을 적용했습니다.


35-44: 앵커 뷰 기반 정확한 위치 계산입니다.

anchorView.post를 사용하여 뷰 레이아웃 완료를 보장하고, measure를 통해 정확한 높이를 계산하여 적절한 yOffset으로 팝업을 위에 표시하도록 구현했습니다.


56-60: 자동 해제 로직과 상태 체크가 안전하게 구현되었습니다.

2초 후 자동으로 팝업을 해제하며, isShowing 체크를 통해 중복 해제를 방지하는 안전한 로직입니다.

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

Labels

✨ feat 신규 기능 구현 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 매장 관리 화면 구성 및 기능 구현

2 participants