Skip to content

Conversation

@m6z1
Copy link
Member

@m6z1 m6z1 commented Jan 10, 2026

📌𝘐𝘴𝘴𝘶𝘦𝘴

📎𝘞𝘰𝘳𝘬 𝘋𝘦𝘴𝘤𝘳𝘪𝘱𝘵𝘪𝘰𝘯

  • 마이페이지 개편 완료!

📷𝘚𝘤𝘳𝘦𝘦𝘯𝘴𝘩𝘰𝘵

💬𝘛𝘰 𝘙𝘦𝘷𝘪𝘦𝘸𝘦𝘳𝘴

Summary by CodeRabbit

Release Notes

  • New Features

    • 개선된 마이 페이지 화면으로 라이브러리 관리 및 장르 선호도 표시 강화
  • Refactor

    • 유지보수성 향상을 위한 내부 코드 구조 재정리
    • 마이 페이지 UI 구성요소 통합

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

@github-actions github-actions bot requested a review from s9hn January 10, 2026 06:31
@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Walkthrough

마이페이지 UI 컴포넌트를 재구조화하여 MyActivity/MyLibrary 모델을 myPage 패키지 루트로 이동하고, 기존 MyActivityFragment와 MyLibraryFragment를 제거한 후 MyPageFragment로 통합했습니다. 패키지 구조 정리 및 레이아웃 재구성이 포함됩니다.

Changes

코호트 / 파일 변경 요약
모델 패키지 이동
app/src/main/java/com/into/websoso/ui/main/myPage/model/ActivitiesModel.kt, ActivityLikeState.kt, Genres.kt, MyActivityUiState.kt, UserActivityModel.kt, UserProfileModel.kt, AttractivePoints.kt
myActivity/myLibrary 서브패키지에서 myPage 패키지로 모델 이동. 모든 참조 위치의 import 경로 업데이트
데이터 매퍼 import 업데이트
app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt, app/src/main/java/com/into/websoso/ui/mapper/ActivityMapper.kt, app/src/main/java/com/into/websoso/ui/mapper/UserMapper.kt
재배치된 모델의 import 경로 갱신. 매핑 로직은 변경 없음
ActivityDetail 관련 파일
app/src/main/java/com/into/websoso/ui/activityDetail/ActivityDetailActivity.kt, ActivityDetailViewModel.kt, adapter/ActivityDetailAdapter.kt, adapter/ActivityDetailViewHolder.kt, model/ActivityDetailUiState.kt
재배치된 모델 import 업데이트. ActivityDetailActivity는 source 기반 분기 로직 제거하고 항상 other_user_activity 제목 사용
MyPage Fragment 통합
app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt
MyLibraryViewModel 및 RestGenrePreferenceAdapter 추가. 라이브러리 관련 UI 상태 관찰자 확장. 장르 선호도, 키워드 칩, 배지 업데이트 로직 추가 (+228/-16)
제거된 Fragment 및 어댑터
app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/MyActivityFragment.kt, MyActivityViewModel.kt, adapter/MyActivityAdapter.kt, adapter/MyActivityViewHolder.kt, app/src/main/java/com/into/websoso/ui/main/myPage/myLibrary/MyLibraryFragment.kt
MyActivityFragment 및 MyLibraryFragment 전체 제거. 관련 어댑터 및 ViewModel도 삭제
이동된 인터페이스 및 어댑터
app/src/main/java/com/into/websoso/ui/main/myPage/ActivityItemClickListener.kt, adapter/RestGenrePreferenceAdapter.kt
ActivityItemClickListener를 myActivity에서 myPage로 이동. RestGenrePreferenceAdapter 패키지를 myLibrary.adapter에서 myPage.adapter로 변경
OtherUserPage 컴포넌트
app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityFragment.kt, OtherUserActivityViewModel.kt, adapter/OtherUserActivityAdapter.kt, adapter/OtherUserActivityViewHolder.kt, model/OtherUserActivityUiState.kt, ../otherUserLibrary/OtherUserLibraryViewModel.kt
재배치된 모델 및 인터페이스의 import 경로 일괄 업데이트
UI 리소스 업데이트
app/src/main/res/layout/fragment_my_page.xml, item_my_activity.xml, app/src/main/res/drawable/btn_profile_edit.xml, core/resource/src/main/res/values/strings.xml
fragment_my_page에 myLibraryViewModel 바인딩 변수 추가. item_my_activity 바인딩 타입 경로 갱신. 새 drawable 추가. 문자열 리소스 업데이트 (my_page_library/activity 제거, my_page_taste_title/badge 추가)
삭제된 레이아웃
app/src/main/res/layout/fragment_my_activity.xml, fragment_my_library.xml
MyActivity 및 MyLibrary 프래그먼트 레이아웃 전체 삭제
MyLibraryUiState 확장
app/src/main/java/com/into/websoso/ui/main/myPage/model/MyLibraryUiState.kt
totalBadgeCount 계산 속성 추가
기타 개선
app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsAdapter.kt
@SuppressLint("DiffUtilEquals") 주석 추가로 lint 경고 억제

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels

🍯 [FEAT], ⚖️ 재상 세훈, 🏹 궁사 명지

Suggested reviewers

  • s9hn

Poem

🐰 마이페이지를 정리하니,
모델들이 새 집을 찾아가고,
Fragment들은 하나로 모여,
구조가 더 깔끔해졌어! ✨
패키지 정리, 아주 멋진데?

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Out of Scope Changes check ❓ Inconclusive 대부분의 변경이 마이페이지 개편 범위 내에 있으나, MyActivityFragment/ViewModel 완전 삭제와 MyLibraryFragment 완전 삭제는 주의깊게 검토해야 할 부분입니다. MyActivityFragment, MyActivityViewModel, MyLibraryFragment 완전 삭제의 정당성과 ActivityDetailActivity로의 기능 이전이 완벽한지 확인하고, 이들 삭제가 의도된 변경인지 명시해주세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 PR의 주요 변경사항을 명확하게 설명하고 있습니다. '마이페이지 개편'은 마이페이지 전체 재구성을 나타내며 대부분의 변경이 이와 관련되어 있습니다.
Description check ✅ Passed PR 설명이 필수 섹션(Issues, Work Description)은 포함하지만 Screenshots와 To Reviewers 섹션이 비어있습니다. 기본적인 정보는 제공되었습니다.
Linked Issues check ✅ Passed 연결된 이슈 #772는 '마이페이지 개편'을 목표로 하며, PR의 변경사항들(레이아웃 구조 변경, 컴포넌트 재배치, 패키지 구조 정리)이 이 목표를 충족합니다.

✏️ 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 (4)
app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityFragment.kt (1)

168-189: 좋아요 토글/카운트 업데이트가 Fragment↔ViewModel 간 의미가 뒤집혀 동작할 가능성이 큽니다(카운트 원복/반대로 저장 위험).
현재 Fragment는 UI를 먼저 토글한 뒤(새 상태) updateActivityLike(view.isSelected, ..., updatedLikeCount)를 호출하고, ViewModel은 isLiked를 기준으로 saveLike(true/false)newLikeCount를 다시 계산하고 있어 상호 모순이 납니다.

제안 수정(계약을 “클릭 전 상태(wasLiked), 클릭 전 카운트(currentLikeCount)”로 통일)
--- a/app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityFragment.kt
+++ b/app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityFragment.kt
@@
             override fun onLikeButtonClick(
                 view: View,
                 feedId: Long,
             ) {
                 val likeCountTextView: TextView = view.findViewById(R.id.tv_my_activity_thumb_up_count)
-                val currentLikeCount = likeCountTextView.text.toString().toInt()
-
-                val updatedLikeCount: Int = if (view.isSelected) {
-                    if (currentLikeCount > 0) currentLikeCount - 1 else 0
-                } else {
-                    currentLikeCount + 1
-                }
-
-                likeCountTextView.text = updatedLikeCount.toString()
-                view.isSelected = !view.isSelected
-
-                otherUserActivityViewModel.updateActivityLike(
-                    view.isSelected,
-                    feedId,
-                    updatedLikeCount,
-                )
+                val wasLiked = view.isSelected
+                val currentLikeCount = likeCountTextView.text.toString().toIntOrNull() ?: 0
+                val targetIsLiked = !wasLiked
+                val updatedLikeCount = if (targetIsLiked) currentLikeCount + 1 else maxOf(0, currentLikeCount - 1)
+
+                // optimistic UI
+                likeCountTextView.text = updatedLikeCount.toString()
+                view.isSelected = targetIsLiked
+
+                // ViewModel에는 "클릭 전 상태/카운트"를 전달 (단일 계약)
+                otherUserActivityViewModel.updateActivityLike(
+                    wasLiked,
+                    feedId,
+                    currentLikeCount,
+                )
             }
app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityViewModel.kt (1)

77-99: 좋아요 저장 파라미터/카운트 계산이 “isLiked 의미”에 강하게 의존합니다 — Fragment와 계약을 명확히 맞추세요.
또한 onFailure { }가 비어 있어 optimistic UI를 쓴다면 최소한 롤백/에러 플래그 반영이 필요합니다.

제안 diff(“클릭 전 상태 wasLiked” 계약 기준 + 실패 시 상태 반영 예시)
--- a/app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityViewModel.kt
+++ b/app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityViewModel.kt
@@
         fun updateActivityLike(
-            isLiked: Boolean,
+            wasLiked: Boolean,
             feedId: Long,
             currentLikeCount: Int,
         ) {
             viewModelScope.launch {
                 runCatching {
-                    if (isLiked) {
-                        feedRepository.saveLike(false, feedId)
-                    } else {
-                        feedRepository.saveLike(true, feedId)
-                    }
+                    val targetIsLiked = !wasLiked
+                    feedRepository.saveLike(targetIsLiked, feedId)
                 }.onSuccess {
-                    val newLikeCount = if (isLiked) currentLikeCount - 1 else currentLikeCount + 1
+                    val targetIsLiked = !wasLiked
+                    val newLikeCount =
+                        if (targetIsLiked) currentLikeCount + 1 else maxOf(0, currentLikeCount - 1)
                     _otherUserActivityUiState.value = _otherUserActivityUiState.value?.copy(
-                        likeState = ActivityLikeState(feedId, !isLiked, newLikeCount),
+                        likeState = ActivityLikeState(feedId, targetIsLiked, newLikeCount),
                     )
-
-                    saveActivityLikeState(feedId, !isLiked, newLikeCount)
+                    saveActivityLikeState(feedId, targetIsLiked, newLikeCount)
                 }.onFailure {
+                    _otherUserActivityUiState.value = _otherUserActivityUiState.value?.copy(error = true)
                 }
             }
         }
app/src/main/java/com/into/websoso/ui/activityDetail/ActivityDetailActivity.kt (2)

234-247: (중요) showPopupMenu가 항상 OtherUser 팝업만 inflate 함 — MY_ACTIVITY 메뉴가 동작 불가
현재 MenuOtherUserActivityPopupBinding.inflate()로 고정되어 MenuMyActivityPopupBinding 분기가 사실상 도달 불가능합니다(수정/삭제 메뉴 미노출, 리포트 메뉴만 노출 위험).

Proposed fix (source에 따라 inflate 분기)
 private fun showPopupMenu(
     view: View,
     feedId: Long,
 ) {
     val inflater = LayoutInflater.from(this)
-    val binding = MenuOtherUserActivityPopupBinding.inflate(inflater)
+    val binding: ViewDataBinding =
+        when (activityDetailViewModel.source) {
+            SOURCE_MY_ACTIVITY -> MenuMyActivityPopupBinding.inflate(inflater)
+            SOURCE_OTHER_USER_ACTIVITY -> MenuOtherUserActivityPopupBinding.inflate(inflater)
+            else -> MenuOtherUserActivityPopupBinding.inflate(inflater)
+        }

     _popupWindow?.dismiss()
     _popupWindow = PopupWindow(binding.root, WRAP_CONTENT, WRAP_CONTENT, true).apply {
         elevation = 2f
         showAsDropDown(view)
     }
     setupPopupMenuClickListeners(binding, feedId)
 }

Also applies to: 249-276


203-224: 좋아요 카운트 파싱이 toInt() 고정 — 비정상 텍스트/공백에서 크래시 가능
TextView.text가 숫자가 아닐 경우 toInt()가 예외를 던질 수 있어 toIntOrNull() 방어가 안전합니다.

Proposed fix (toIntOrNull + 기본값)
 val likeCountTextView: TextView = view.findViewById(tv_my_activity_thumb_up_count)
-val currentLikeCount = likeCountTextView.text.toString().toInt()
+val currentLikeCount = likeCountTextView.text.toString().toIntOrNull() ?: 0
🤖 Fix all issues with AI agents
In @app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt:
- Around line 275-303: updateNovelPreferencesKeywords currently only adds new
chips and never removes or updates existing ones, causing stale chips when
counts drop or names change; modify updateNovelPreferencesKeywords to fully
re-render the chip container by clearing binding.wcgMyLibraryAttractivePoints
(removeAllViews or equivalent) before iterating novelPreferences.keywords and
then add createKeywordChip(...) for each keyword (or alternatively compute the
set difference and remove only obsolete children), ensuring the UI reflects the
current novelPreferences.keywords exactly.

In @app/src/main/res/layout/fragment_my_page.xml:
- Around line 261-270: The layout TextView with id
tv_my_linear_storage_quit_title references a possibly misspelled string resource
my_library_quite; verify intended text and if it should be "quit" rename the
string resource key to my_library_quit (and update all usages) or correct the
TextView to use the existing, correctly spelled key; ensure resource name and
value/usage are consistent across the project.
- Around line 58-67: Clickable ImageView(s) like iv_my_page_sticky_go_to_setting
are missing contentDescription which breaks accessibility and lint; add
android:contentDescription="@string/..." to the ImageView(s) and create
corresponding entries in strings.xml (e.g., "settings", "toggle_notifications"
or similar descriptive labels) so TalkBack announces the purpose; apply the same
change to the other clickable ImageView(s) referenced around lines 434-444.
- Around line 521-553: The ConstraintLayout with id
cl_my_library_attractive_points uses layout_height="0dp" but only has a top
constraint, which can collapse its height; fix by either changing
cl_my_library_attractive_points to layout_height="wrap_content" or add a proper
bottom constraint (for example constrain its bottom to the top of
wcg_my_library_attractive_points or to parent) so the view can measure correctly
and the contained TextView (tv_my_library_attractive_points) remains visible.
- Around line 277-290: The divider View and the ConstraintLayout
cl_my_library_genre_preference both use
app:layout_constraintTop_toBottomOf="@id/cl_my_page_user_profile", causing
overlap; give the View a unique id (e.g., @+id/divider_my_page) and change
cl_my_library_genre_preference's top constraint to
app:layout_constraintTop_toBottomOf="@id/divider_my_page" so the section is
positioned below the divider instead of the same anchor.
🧹 Nitpick comments (7)
app/src/main/res/drawable/btn_profile_edit.xml (1)

1-14: 드로어블 구현은 올바르나, 색상 리소스 사용을 권장합니다.

벡터 드로어블이 올바르게 정의되었으며 프로필 수정 버튼으로 적절해 보입니다. 다만 하드코딩된 색상 값(#ffffff, #DDDDE3, #949399) 대신 색상 리소스(@color/...)를 사용하면 테마 지원과 유지보수성이 향상됩니다.

♻️ 색상 리소스를 사용한 개선안

먼저 res/values/colors.xml에 색상을 정의하세요:

<color name="profile_edit_background">#FFFFFF</color>
<color name="profile_edit_stroke">#DDDDE3</color>
<color name="profile_edit_icon">#949399</color>

그런 다음 드로어블에서 색상 리소스를 참조하세요:

   <path
       android:strokeWidth="1"
       android:pathData="M13.481,0.5C20.608,0.5 26.5,6.378 26.5,13.494C26.5,20.621 20.621,26.5 13.494,26.5C6.379,26.5 0.5,20.621 0.5,13.494C0.5,6.38 6.366,0.5 13.481,0.5Z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#DDDDE3"/>
+      android:fillColor="@color/profile_edit_background"
+      android:strokeColor="@color/profile_edit_stroke"/>
   <path
       android:pathData="M18.208,11.335L19.62,9.925C20.319,9.221 20.345,8.451 19.711,7.799L19.205,7.277C18.571,6.637 17.781,6.703 17.095,7.394L15.683,8.79L18.208,11.335ZM10.644,18.926L17.485,12.032L14.973,9.514L8.131,16.381L6.862,19.461C6.72,19.852 7.121,20.283 7.51,20.139L10.644,18.926Z"
-      android:fillColor="#949399"/>
+      android:fillColor="@color/profile_edit_icon"/>
app/src/main/java/com/into/websoso/ui/main/myPage/model/AttrativePoints.kt (1)

1-16: 파일명 오타(AttrativePoints.kt)는 정리 권장
클래스명이 AttractivePoints라서 파일명도 AttractivePoints.kt로 맞추는 편이 좋습니다.

app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityFragment.kt (1)

23-26: 패키지 이동 반영은 OK인데, otherUserPagemyPage 타입에 직접 의존하는 결합도가 커졌습니다.
가능하면 ActivityItemClickListener, UserProfileModel 같은 “공유 UI 모델/리스너”는 feature 공통 모듈(또는 ui.model 성격의 패키지)로 분리하는 쪽이 장기 유지보수에 안전합니다.

app/src/main/java/com/into/websoso/ui/mapper/UserMapper.kt (1)

17-22: MyProfileModel.toUi(): UserProfileModel vs MyProfileEntity.toUserProfileModel()가 역할/네이밍이 겹쳐 혼란 소지가 있습니다.
한쪽으로 통일(예: toUserProfileModel()만 유지)하거나 toUi() 네이밍을 더 구체화하는 정리가 있으면 좋겠습니다.

Also applies to: 31-35

app/src/main/java/com/into/websoso/ui/main/myPage/MyLibraryViewModel.kt (1)

116-119: AttractivePoints.Companion.fromString(...)는 불필요하게 장황합니다(가능하면 AttractivePoints.fromString(...)로).

제안 diff
-                AttractivePoints.Companion.fromString(point)?.korean
+                AttractivePoints.fromString(point)?.korean
app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt (2)

129-192: 로딩/에러 뷰(wllMyPage)를 두 observer가 동시에 제어 — 상태 덮어쓰기/깜빡임 위험
myPageViewModel.uiStatemyLibraryViewModel.uiState가 같은 로딩/에러 레이아웃을 각각 토글해서, 한쪽이 “정상”이어도 다른쪽이 “로딩”이면 UI가 흔들릴 수 있습니다(특히 네트워크 타이밍). “최종 표시 상태”를 한 곳에서 합성해서 결정하는 방식이 안전합니다.

Also applies to: 203-220


349-358: FragmentResult key가 하드코딩 문자열 — 상수화 권장(오타/호환성 리스크)
"NAVIGATE_TO_LIBRARY_FRAGMENT"는 동일 키를 쓰는 쪽과 함께 const val로 공유하는 편이 안전합니다.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eae3f8b and 326cdca.

📒 Files selected for processing (39)
  • app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt
  • app/src/main/java/com/into/websoso/ui/activityDetail/ActivityDetailActivity.kt
  • app/src/main/java/com/into/websoso/ui/activityDetail/ActivityDetailViewModel.kt
  • app/src/main/java/com/into/websoso/ui/activityDetail/adapter/ActivityDetailAdapter.kt
  • app/src/main/java/com/into/websoso/ui/activityDetail/adapter/ActivityDetailViewHolder.kt
  • app/src/main/java/com/into/websoso/ui/activityDetail/model/ActivityDetailUiState.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/ActivityItemClickListener.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/MyLibraryViewModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/adapter/MyPageViewPagerAdapter.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/adapter/RestGenrePreferenceAdapter.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/ActivitiesModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/ActivityLikeState.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/AttrativePoints.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/Genres.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/MyActivityUiState.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/MyLibraryUiState.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/UserActivityModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/UserProfileModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/MyActivityFragment.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/MyActivityViewModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/adapter/MyActivityAdapter.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/adapter/MyActivityViewHolder.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/model/UserActivityModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myLibrary/MyLibraryFragment.kt
  • app/src/main/java/com/into/websoso/ui/mapper/ActivityMapper.kt
  • app/src/main/java/com/into/websoso/ui/mapper/UserMapper.kt
  • app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityFragment.kt
  • app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityViewModel.kt
  • app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/adapter/OtherUserActivityAdapter.kt
  • app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/adapter/OtherUserActivityViewHolder.kt
  • app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/model/OtherUserActivityUiState.kt
  • app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserLibrary/OtherUserLibraryViewModel.kt
  • app/src/main/res/drawable/btn_profile_edit.xml
  • app/src/main/res/layout/fragment_my_activity.xml
  • app/src/main/res/layout/fragment_my_library.xml
  • app/src/main/res/layout/fragment_my_page.xml
  • app/src/main/res/layout/item_my_activity.xml
  • core/resource/src/main/res/values/strings.xml
💤 Files with no reviewable changes (9)
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/adapter/MyActivityAdapter.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/model/UserActivityModel.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/adapter/MyPageViewPagerAdapter.kt
  • app/src/main/res/layout/fragment_my_activity.xml
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/MyActivityFragment.kt
  • app/src/main/res/layout/fragment_my_library.xml
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/adapter/MyActivityViewHolder.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myLibrary/MyLibraryFragment.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/myActivity/MyActivityViewModel.kt
🧰 Additional context used
🧬 Code graph analysis (1)
app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt (1)
app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserLibrary/OtherUserLibraryFragment.kt (6)
  • onStorageButtonClick (210-222)
  • updateRestGenrePreferenceVisibility (128-133)
  • updateNovelPreferencesKeywords (182-186)
  • updateDominantGenres (198-208)
  • applyTextColors (135-180)
  • createKeywordChip (188-196)
🔇 Additional comments (29)
app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt (1)

26-26: 패키지 재구성이 정확하게 완료되었습니다.

Genres 클래스의 import 경로가 올바르게 업데이트되었고, 파일 내에서 적절하게 사용되고 있습니다. 코드베이스에 이전 패키지 경로 참조가 남아있지 않습니다.

app/src/main/java/com/into/websoso/ui/main/myPage/model/Genres.kt (2)

1-1: 패키지 이동이 일관되게 적용되었습니다.

다른 모델 클래스들과 함께 myPage.model로 통합되어 구조가 개선되었습니다.


19-24: 코드 간소화가 적절합니다.

Genres.entriesentries로 변경한 것은 올바른 개선입니다. companion object 스코프 내에서 명시적인 Genres. 접두사는 불필요하므로 코드가 더 간결해졌습니다.

app/src/main/java/com/into/websoso/ui/main/myPage/ActivityItemClickListener.kt (1)

1-1: 패키지 단순화가 완료되었습니다.

인터페이스를 myActivity 서브패키지에서 myPage로 이동한 변경사항을 검증했습니다. 모든 의존 파일(6개 어댑터 및 뷰홀더)에서 새 패키지 경로로 import가 일관되게 업데이트되었으며, 이전 패키지 경로에 대한 참조는 남아있지 않습니다.

app/src/main/java/com/into/websoso/ui/main/myPage/adapter/RestGenrePreferenceAdapter.kt (1)

1-1: 패키지 재구성이 일관성 있게 적용되었는지 확인이 필요합니다.

myLibrary.adapter에서 myPage.adapter로의 이동이 전체 리팩토링 계획과 일치하는지 검증하기 위해, MyPageFragment 및 관련 ViewModel에서 이 어댑터의 import 경로가 올바르게 업데이트되었는지 반드시 확인하세요. 특히 다음을 검증하시기 바랍니다:

  • 이전 패키지 경로(com.into.websoso.ui.main.myPage.myLibrary.adapter.RestGenrePreferenceAdapter)에 대한 참조가 모두 제거되었는지 확인
  • 새 패키지 경로(com.into.websoso.ui.main.myPage.adapter.RestGenrePreferenceAdapter)로의 import 업데이트 확인
  • RestGenrePreferenceAdapter를 사용하는 모든 파일에서 import 문이 정확하게 업데이트되었는지 확인
app/src/main/java/com/into/websoso/ui/main/myPage/model/ActivitiesModel.kt (1)

1-1: 패키지 구조 개선이 적절합니다.

myActivity.model에서 myPage.model로의 패키지 이동은 구조를 더 평탄하게 만들어 유지보수성을 향상시킵니다. 코드베이스 전체에서 모든 import 참조가 새 패키지 경로(com.into.websoso.ui.main.myPage.model)로 일관되게 업데이트되었습니다.

app/src/main/java/com/into/websoso/ui/main/myPage/model/ActivityLikeState.kt (1)

1-1: ActivityLikeState의 패키지 이동이 올바르게 완료되었습니다.

myPage.model 패키지로의 이동 후 모든 의존 파일의 import가 정확하게 업데이트되었습니다:

  • ActivityDetailViewModel.kt - 올바른 import ✓
  • OtherUserActivityViewModel.kt - 올바른 import ✓
  • OtherUserActivityUiState.kt - 올바른 import ✓

이전 패키지 경로에 대한 참조는 남아있지 않습니다. 모델 구조 통합이 적절하게 진행되었습니다.

app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/adapter/OtherUserActivityViewHolder.kt (1)

8-9: LGTM! Import 경로 업데이트가 올바르게 적용되었습니다.

패키지 리팩토링에 맞춰 import 경로가 정확하게 수정되었고, ViewHolder의 로직은 변경사항이 없어 기존 동작이 유지됩니다.

app/src/main/java/com/into/websoso/ui/main/myPage/model/MyActivityUiState.kt (1)

1-3: 패키지 및 import 경로가 올바르게 업데이트되었습니다.

UI 상태 클래스의 로직 변경 없이 패키지 구조만 깔끔하게 정리되었습니다.

app/src/main/java/com/into/websoso/ui/main/myPage/model/MyLibraryUiState.kt (2)

1-1: 패키지 경로가 올바르게 업데이트되었습니다.

중앙 집중식 모델 패키지로의 이동이 일관되게 적용되었습니다.


16-19: 계산 프로퍼티 구현이 올바르게 작동합니다.

totalBadgeCounttopGenresrestGenres 목록의 모든 배지 수를 정확하게 합산하며, MyPageFragment.kt의 184번 줄에서 updateGenreBadgeTitle() 메서드에 올바르게 전달되고 있습니다. 계산 프로퍼티로 구현되어 있어 접근 시마다 재계산되는데, 장르 목록의 크기가 일반적으로 작으므로 성능 영향은 무시할 수 있습니다.

app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/model/OtherUserActivityUiState.kt (1)

3-4: LGTM! Import 경로가 새로운 패키지 구조에 맞게 업데이트되었습니다.

패키지 리팩토링에 따른 일관된 변경사항이며, UI 상태 클래스의 동작에는 영향이 없습니다.

app/src/main/java/com/into/websoso/ui/main/myPage/model/UserProfileModel.kt (1)

1-1: 모든 import 참조가 업데이트되었는지 수동 검증 필요합니다.

패키지 리팩토링이 적용되었으나, 다음 항목들을 확인해야 합니다:

  • 이전 패키지 경로 com.into.websoso.ui.main.myPage.myActivity.model.UserProfileModel을 참조하는 import 남아있는지 확인
  • com.into.websoso.ui.main.myPage.model.UserProfileModel로 모든 import이 업데이트되었는지 확인
  • 특히 build.gradle, 의존성 설정, 테스트 코드에서도 참조 확인

코드 컴파일 시 누락된 import 관련 오류가 없으면 완전한 마이그레이션으로 판단할 수 있습니다.

app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserLibrary/OtherUserLibraryViewModel.kt (1)

7-10: 모델 패키지 이동에 따른 import 정리 OK
패키지 리오그 후 누락된 참조가 없는지만 assembleDebug/CI로 확인되면 충분해 보입니다.

app/src/main/java/com/into/websoso/ui/activityDetail/ActivityDetailViewModel.kt (1)

10-14: import 경로 변경 반영 OK
모델 통합 패키지로의 이동 의도에 맞게 잘 맞춰졌습니다.

app/src/main/java/com/into/websoso/ui/mapper/ActivityMapper.kt (1)

3-6: import 경로 변경만 반영된 점 확인 (LGTM)
매핑 로직은 그대로라 리스크가 낮습니다.

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

6-16: 마이라이브러리ViewModel 바인딩은 정상적으로 설정됨
Fragment에서 bindViewModel() 메서드(라인 89-93)를 통해 myLibraryViewModellifecycleOwner가 모두 제대로 연결되어 있습니다. 레이아웃에서의 참조는 런타임 문제를 일으키지 않습니다.

Likely an incorrect or invalid review comment.

app/src/main/java/com/into/websoso/ui/mapper/UserMapper.kt (1)

6-6: 모델 패키지 이동(import) 반영은 문제 없어 보입니다.

app/src/main/java/com/into/websoso/ui/main/myPage/MyLibraryViewModel.kt (1)

1-10: 패키지/모델 import 정리는 PR 목표(구조 재정리)와 일관됩니다.

app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/OtherUserActivityViewModel.kt (1)

9-9: 모델 패키지 이동(import) 반영은 OK입니다.

app/src/main/java/com/into/websoso/ui/activityDetail/model/ActivityDetailUiState.kt (1)

3-3: 모델 패키지 이동(import)만 반영되어 있고, UiState 구조 변경은 없어 보여 안전합니다.

app/src/main/java/com/into/websoso/ui/main/myPage/model/UserActivityModel.kt (1)

1-8: LGTM!

새로운 패키지 위치에 모델 클래스가 적절하게 정의되었습니다. 데이터 클래스 구조가 간결하고 명확합니다.

app/src/main/java/com/into/websoso/ui/activityDetail/adapter/ActivityDetailAdapter.kt (1)

8-9: LGTM!

import 경로 변경이 다른 파일들과 일관되게 적용되었습니다.

app/src/main/java/com/into/websoso/ui/otherUserPage/otherUserActivity/adapter/OtherUserActivityAdapter.kt (1)

8-9: LGTM!

import 경로 변경이 일관되게 적용되었습니다.

core/resource/src/main/res/values/strings.xml (1)

218-219: 새로운 문자열 리소스가 올바르게 추가되고 삭제된 리소스는 깨끗하게 제거되었습니다.

마이페이지 개편에 맞춰 추가된 my_page_taste_titlemy_page_badge 문자열이 레이아웃 및 코드에서 모두 올바르게 사용되고 있으며, 삭제된 my_page_librarymy_page_activity는 코드베이스 어디에서도 참조되지 않습니다. 특히 my_page_badge%d 플레이스홀더가 MyPageFragment.kt에서 올바른 파라미터와 함께 처리되고 있습니다.

app/src/main/java/com/into/websoso/ui/activityDetail/adapter/ActivityDetailViewHolder.kt (1)

8-9: 패키지 구조 재정리가 올바르게 적용되었습니다.

이전 com.into.websoso.ui.main.myPage.myActivitycom.into.websoso.ui.main.myPage.myActivity.model 패키지 경로의 import가 코드베이스 전체에서 완전히 제거되었으며, 새로운 import 경로로 정상 변경되었습니다.

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

10-20: 데이터바인딩 타입 경로 변경 반영 OK (패키지 이동 대응)
XML 변수 타입들이 com.into.websoso.ui.main.myPage.modelcom.into.websoso.ui.main.myPage로 일관되게 갱신되어 리팩터링 목적에 맞습니다.

app/src/main/java/com/into/websoso/ui/activityDetail/ActivityDetailActivity.kt (2)

111-113: 타이틀이 항상 other_user_page_activity로 고정됨 — source별 분기 필요 여부 확인
SOURCE_MY_ACTIVITY로 진입하는 경우에도 동일 타이틀이 의도인지 확인이 필요합니다.


165-182: getUserProfile()에 else 추가는 방어적으로 좋음
source 미지정/추가 케이스에서 NPE 대신 null로 안전하게 떨어지도록 한 점은 좋습니다.

Comment on lines +275 to +303
private fun updateNovelPreferencesKeywords(novelPreferences: NovelPreferenceEntity) {
val existingKeywords = mutableSetOf<String>()

for (i in 0 until binding.wcgMyLibraryAttractivePoints.childCount) {
val chip = binding.wcgMyLibraryAttractivePoints.getChildAt(i) as? Chip
chip?.text?.let { existingKeywords.add(it.toString()) }
}

novelPreferences.keywords.forEach { keyword ->
val keywordText = "${keyword.keywordName} ${keyword.keywordCount}"
if (!existingKeywords.contains(keywordText)) {
binding.wcgMyLibraryAttractivePoints.addView(createKeywordChip(keyword))
existingKeywords.add(keywordText)
}
}
}

private fun createKeywordChip(data: NovelPreferenceEntity.KeywordEntity): Chip =
WebsosoChip(requireContext()).apply {
text = "${data.keywordName} ${data.keywordCount}"
isCheckable = false
isChecked = false
isEnabled = false

setChipBackgroundColorResource(primary_50_F1EFFF)
setTextColor(ContextCompat.getColor(requireContext(), primary_100_6A5DFD))
setTextAppearance(body2)
}

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

키워드 칩 업데이트가 ‘추가만’ 됨 — 감소/변경 시 오래된 칩이 남을 수 있음
existingKeywords로 중복 추가는 막지만, 키워드 수가 줄거나 keywordCount가 변하면 기존 칩이 그대로 남아 UI가 누적/불일치할 수 있습니다.

Proposed fix (현재 상태로 재렌더링; 가장 단순/안전)
 private fun updateNovelPreferencesKeywords(novelPreferences: NovelPreferenceEntity) {
-    val existingKeywords = mutableSetOf<String>()
-
-    for (i in 0 until binding.wcgMyLibraryAttractivePoints.childCount) {
-        val chip = binding.wcgMyLibraryAttractivePoints.getChildAt(i) as? Chip
-        chip?.text?.let { existingKeywords.add(it.toString()) }
-    }
-
-    novelPreferences.keywords.forEach { keyword ->
-        val keywordText = "${keyword.keywordName} ${keyword.keywordCount}"
-        if (!existingKeywords.contains(keywordText)) {
-            binding.wcgMyLibraryAttractivePoints.addView(createKeywordChip(keyword))
-            existingKeywords.add(keywordText)
-        }
-    }
+    binding.wcgMyLibraryAttractivePoints.removeAllViews()
+    novelPreferences.keywords.forEach { keyword ->
+        binding.wcgMyLibraryAttractivePoints.addView(createKeywordChip(keyword))
+    }
 }
🤖 Prompt for AI Agents
In @app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt around
lines 275 - 303, updateNovelPreferencesKeywords currently only adds new chips
and never removes or updates existing ones, causing stale chips when counts drop
or names change; modify updateNovelPreferencesKeywords to fully re-render the
chip container by clearing binding.wcgMyLibraryAttractivePoints (removeAllViews
or equivalent) before iterating novelPreferences.keywords and then add
createKeywordChip(...) for each keyword (or alternatively compute the set
difference and remove only obsolete children), ensuring the UI reflects the
current novelPreferences.keywords exactly.

Comment on lines +58 to +67
<ImageView
android:id="@+id/iv_my_page_sticky_go_to_setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:padding="10dp"
android:src="@drawable/ic_settings"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
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

클릭 가능한 ImageView에 contentDescription 누락 (접근성/린트)
설정 아이콘, 토글 아이콘은 사용자 액션 요소라 contentDescription이 필요합니다(특히 TalkBack).

Proposed fix (문구는 리소스 추가 권장)
 <ImageView
     android:id="@+id/iv_my_page_sticky_go_to_setting"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:contentDescription="@string/a11y_go_to_settings"
     android:layout_marginEnd="12dp"
     android:padding="10dp"
     android:src="@drawable/ic_settings"
     app:layout_constraintBottom_toBottomOf="parent"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent" />

 <ImageView
     android:id="@+id/iv_my_library_genre_preference_path"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:contentDescription="@string/a11y_toggle_genre_list"
     android:layout_marginTop="12dp"
     android:onClick="@{() -> myLibraryViewModel.updateToggleGenresVisibility()}"
     android:padding="20dp"
     android:src="@{myLibraryViewModel.uiState.isGenreListVisible ? @drawable/ic_my_library_upper_path : @drawable/ic_my_library_lower_path}"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@id/lv_my_library_rest_genre" />

Also applies to: 434-444

🤖 Prompt for AI Agents
In @app/src/main/res/layout/fragment_my_page.xml around lines 58 - 67, Clickable
ImageView(s) like iv_my_page_sticky_go_to_setting are missing contentDescription
which breaks accessibility and lint; add
android:contentDescription="@string/..." to the ImageView(s) and create
corresponding entries in strings.xml (e.g., "settings", "toggle_notifications"
or similar descriptive labels) so TalkBack announces the purpose; apply the same
change to the other clickable ImageView(s) referenced around lines 434-444.

Comment on lines +261 to +270
<TextView
android:id="@+id/tv_my_linear_storage_quit_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_weight="1"
android:text="@string/my_library_quite"
android:textAppearance="@style/body5"
android:textColor="@color/black" />

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

문자열 리소스 키 my_library_quite 오타 가능성 확인
의도한 값이 “quit”라면 리소스/표기 일관성을 위해 확인이 필요합니다.

🤖 Prompt for AI Agents
In @app/src/main/res/layout/fragment_my_page.xml around lines 261 - 270, The
layout TextView with id tv_my_linear_storage_quit_title references a possibly
misspelled string resource my_library_quite; verify intended text and if it
should be "quit" rename the string resource key to my_library_quit (and update
all usages) or correct the TextView to use the existing, correctly spelled key;
ensure resource name and value/usage are consistent across the project.

Comment on lines +277 to +290
<View
android:layout_width="0dp"
android:layout_height="3dp"
android:background="@color/gray_50_F4F5F8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_my_page_user_profile" />

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_my_library_genre_preference"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin">
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/cl_my_page_user_profile"
tools:layout_editor_absoluteX="0dp">
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

구분선(View)과 다음 섹션이 같은 Top 제약을 사용해 겹칠 가능성 큼
view(Line 277-283)는 cl_my_page_user_profile 아래에 붙어있는데, 바로 다음 cl_my_library_genre_preference도 동일하게 cl_my_page_user_profile 아래로 제약(Line 289)이라 겹칠 수 있습니다.

Proposed fix
 <View
     android:layout_width="0dp"
     android:layout_height="3dp"
     android:background="@color/gray_50_F4F5F8"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@id/cl_my_page_user_profile" />

 <androidx.constraintlayout.widget.ConstraintLayout
     android:id="@+id/cl_my_library_genre_preference"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    app:layout_constraintTop_toBottomOf="@id/cl_my_page_user_profile"
+    app:layout_constraintTop_toBottomOf="@id/view_my_page_novel_preference_divider"
     tools:layout_editor_absoluteX="0dp">
🤖 Prompt for AI Agents
In @app/src/main/res/layout/fragment_my_page.xml around lines 277 - 290, The
divider View and the ConstraintLayout cl_my_library_genre_preference both use
app:layout_constraintTop_toBottomOf="@id/cl_my_page_user_profile", causing
overlap; give the View a unique id (e.g., @+id/divider_my_page) and change
cl_my_library_genre_preference's top constraint to
app:layout_constraintTop_toBottomOf="@id/divider_my_page" so the section is
positioned below the divider instead of the same anchor.

Comment on lines +328 to +418
<TextView
android:id="@+id/tv_my_library_dominant_genre_first_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@{myLibraryViewModel.uiState.topGenres[0].genreName}"
android:textAppearance="@style/title3"
android:textColor="@color/black"
tools:text="로판" />

<TextView
android:id="@+id/tv_my_library_dominant_genre_first_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text='@{String.format(@string/my_library_genre_count, myLibraryViewModel.uiState.topGenres[0].genreCount)}'
android:textAppearance="@style/body5"
android:textColor="@color/gray_200_949399"
tools:text="12편" />

</LinearLayout>

<LinearLayout
android:id="@+id/ll_my_library_dominant_genre_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">

<ImageView
android:id="@+id/iv_my_library_dominant_genre_second_logo"
android:layout_width="30dp"
android:layout_height="37dp"
tools:src="@drawable/ic_novel_detail_genre_test" />

<TextView
android:id="@+id/tv_my_library_dominant_genre_second_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@{myLibraryViewModel.uiState.topGenres[1].genreName}"
android:textAppearance="@style/title3"
android:textColor="@color/black"
tools:text="로판" />

<TextView
android:id="@+id/tv_my_library_dominant_genre_second_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text='@{String.format(@string/my_library_genre_count, myLibraryViewModel.uiState.topGenres[1].genreCount)}'
android:textAppearance="@style/body5"
android:textColor="@color/gray_200_949399"
tools:text="12편" />

</LinearLayout>

<LinearLayout
android:id="@+id/ll_my_library_dominant_genre_third"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">

<ImageView
android:id="@+id/iv_my_library_dominant_genre_third_logo"
android:layout_width="30dp"
android:layout_height="37dp"
tools:src="@drawable/ic_novel_detail_genre_test" />

<TextView
android:id="@+id/tv_my_library_dominant_genre_third_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@{myLibraryViewModel.uiState.topGenres[2].genreName}"
android:textAppearance="@style/title3"
android:textColor="@color/black"
tools:text="로판" />

<TextView
android:id="@+id/tv_my_library_dominant_genre_third_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text='@{String.format(@string/my_library_genre_count, myLibraryViewModel.uiState.topGenres[2].genreCount)}'
android:textAppearance="@style/body5"
android:textColor="@color/gray_200_949399"
tools:text="12편" />
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

DataBinding에서 topGenres[0..2] 직접 인덱싱은 IndexOutOfBounds 위험
선호 장르가 3개 미만인 케이스(신규/데이터 부족)에서 바인딩 평가 중 크래시 날 수 있습니다. “항상 3개 채워서 내려준다”를 보장하거나, XML에서 size 가드/visibility 처리가 필요합니다.

Proposed fix (XML 가드 예시)
-android:text="@{myLibraryViewModel.uiState.topGenres[0].genreName}"
+android:text="@{myLibraryViewModel.uiState.topGenres.size > 0 ? myLibraryViewModel.uiState.topGenres.get(0).genreName : ``}"

-android:text='@{String.format(@string/my_library_genre_count, myLibraryViewModel.uiState.topGenres[0].genreCount)}'
+android:text='@{myLibraryViewModel.uiState.topGenres.size > 0 ? String.format(@string/my_library_genre_count, myLibraryViewModel.uiState.topGenres.get(0).genreCount) : ``}'

Comment on lines +424 to +445
<ListView
android:id="@+id/lv_my_library_rest_genre"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="40dp"
android:layout_marginTop="32dp"
android:divider="@null"
app:layout_constraintTop_toBottomOf="@id/ll_my_library_dominant_genre"
tools:layout_editor_absoluteX="40dp" />

<ImageView
android:id="@+id/iv_my_page_sticky_go_to_setting"
<ImageView
android:id="@+id/iv_my_library_genre_preference_path"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:onClick="@{() -> myLibraryViewModel.updateToggleGenresVisibility()}"
android:padding="20dp"
android:src="@{myLibraryViewModel.uiState.isGenreListVisible ? @drawable/ic_my_library_upper_path : @drawable/ic_my_library_lower_path}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/lv_my_library_rest_genre" />

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

ListView0dp 높이 + 단일 제약이라 화면에 안 보일 수 있음 (+ NestedScrollView 안 ListView는 비권장)
현재 lv_my_library_rest_genrelayout_height="0dp"인데 bottom 제약이 없어 높이가 0으로 계산될 소지가 큽니다. 또한 NestedScrollView 안 ListView는 측정/스크롤 이슈가 자주 나서 RecyclerView 전환을 권장합니다.

Proposed fix (최소한 보이게)
 <ListView
     android:id="@+id/lv_my_library_rest_genre"
     android:layout_width="match_parent"
-    android:layout_height="0dp"
+    android:layout_height="wrap_content"
     android:layout_marginHorizontal="40dp"
     android:layout_marginTop="32dp"
     android:divider="@null"
     app:layout_constraintTop_toBottomOf="@id/ll_my_library_dominant_genre"
     tools:layout_editor_absoluteX="40dp" />

Comment on lines +521 to 553
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_my_library_attractive_points"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="20dp"
android:background="@drawable/bg_my_library_gray50_radius_12dp"
android:paddingVertical="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_my_library_novel_preference_title">

<TextView
android:id="@+id/tv_my_library_attractive_points"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:padding="10dp"
android:src="@drawable/ic_settings"
android:text="@{myLibraryViewModel.attractivePointsText}"
android:textAppearance="@style/title2"
android:textColor="@color/gray_300_52515F"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="현캐릭터,소재가 매력적인 작품" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.appcompat.widget.Toolbar>

</com.google.android.material.appbar.CollapsingToolbarLayout>
<com.into.websoso.core.common.ui.custom.WebsosoChipGroup
android:id="@+id/wcg_my_library_attractive_points"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/cl_my_library_attractive_points" />

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

cl_my_library_attractive_points0dp 높이 + 단일 제약이라 내용이 0 높이로 사라질 수 있음
layout_height="0dp"는 (보통) top/bottom 제약이 같이 있어야 합니다. 현재는 top만 있어 0으로 수렴할 가능성이 큽니다.

Proposed fix
 <androidx.constraintlayout.widget.ConstraintLayout
     android:id="@+id/cl_my_library_attractive_points"
     android:layout_width="match_parent"
-    android:layout_height="0dp"
+    android:layout_height="wrap_content"
     android:layout_marginTop="20dp"
     android:background="@drawable/bg_my_library_gray50_radius_12dp"
     android:paddingVertical="20dp"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@id/tv_my_library_novel_preference_title">
🤖 Prompt for AI Agents
In @app/src/main/res/layout/fragment_my_page.xml around lines 521 - 553, The
ConstraintLayout with id cl_my_library_attractive_points uses
layout_height="0dp" but only has a top constraint, which can collapse its
height; fix by either changing cl_my_library_attractive_points to
layout_height="wrap_content" or add a proper bottom constraint (for example
constrain its bottom to the top of wcg_my_library_attractive_points or to
parent) so the view can measure correctly and the contained TextView
(tv_my_library_attractive_points) remains visible.

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

🧹 Nitpick comments (1)
app/src/main/java/com/into/websoso/ui/main/myPage/model/AttractivePoints.kt (1)

14-14: values() 대신 entries를 사용하는 것을 권장합니다.

이미 이 파일을 리팩토링하는 김에, Kotlin 1.9부터 권장되는 entries 프로퍼티로 업데이트하면 코드를 현대화할 수 있습니다.

♻️ 제안하는 수정 사항
-        fun fromString(value: String): AttractivePoints? = values().find { it.name.equals(value, ignoreCase = true) }
+        fun fromString(value: String): AttractivePoints? = entries.find { it.name.equals(value, ignoreCase = true) }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 326cdca and e8ff81b.

📒 Files selected for processing (2)
  • app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsAdapter.kt
  • app/src/main/java/com/into/websoso/ui/main/myPage/model/AttractivePoints.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
app/src/main/java/com/into/websoso/ui/main/myPage/model/AttractivePoints.kt (1)

1-1: 패키지 구조 개선이 적절합니다.

모델 클래스를 myPage.model로 중앙 집중화하는 리팩토링이 올바르게 적용되었습니다. AI 요약에 따르면 관련 임포트들도 코드베이스 전체에서 업데이트되어 일관성이 유지되고 있습니다.

app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsAdapter.kt (1)

3-3: 현재 구현은 올바릅니다. 별도의 변경이 필요 없습니다.

PopularFeedEntity는 데이터 클래스이므로 Kotlin에서 자동으로 생성된 equals() 메서드를 통해 == 연산자가 모든 필드를 올바르게 비교합니다. DiffUtil의 "DiffUtilEquals" 린트 경고는 적절한 equals() 구현이 없는 객체에 대해 ==를 사용할 때 발생하는 경고이지만, 이 경우 데이터 클래스가 올바른 구현을 제공하므로 @SuppressLint 어노테이션은 정당합니다.

인기 피드 리스트는 일반적으로 작은 크기이고, 현재의 간단하고 명확한 구현이 이 목적에 가장 적합합니다.

@m6z1 m6z1 merged commit 80d78a2 into develop Jan 10, 2026
1 of 2 checks passed
@m6z1 m6z1 deleted the feat/772 branch January 10, 2026 06:53
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.

feat: 마이페이지 개편(parent issue)

2 participants