Skip to content

feat: 홈 화면 '지금 뜨는 글'#885

Merged
devfeijoa merged 12 commits into
developfrom
feat/881
Jun 3, 2026
Merged

feat: 홈 화면 '지금 뜨는 글'#885
devfeijoa merged 12 commits into
developfrom
feat/881

Conversation

@devfeijoa

@devfeijoa devfeijoa commented May 27, 2026

Copy link
Copy Markdown
Contributor

📌𝘐𝘴𝘴𝘶𝘦𝘴

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

  • 홈 화면 중 지끔 뜨는 글 부분을 기능추가 및 변경

작업 내용

홈 화면의 지금 뜨는 글 컴포넌트를 변경된 피그마 디자인과 요구사항에 맞게 수정했습니다.

  • 지금 뜨는 글을 한 페이지당 최대 2개씩 노출하도록 변경
  • 각 피드 카드 전체를 터치 영역으로 유지하고, 해당 피드 상세로 이동하도록 처리
  • /feeds/popular 응답만으로 부족한 작품 제목/공개 여부/작품 연결 정보를 피드 상세 조회로 보강
  • 작품이 연결되어 있고 공개 상태인 인기 피드만 노출되도록 필터링
  • 스포일러 글은 본문을 노출하지 않고 스포일러가 포함된 글 보기 문구로 표시
  • 썸네일 우측 하단에 장르 프레임과 장르 이미지를 함께 노출
  • 피그마 기준으로 제목/본문 스타일, 간격, 썸네일 크기, 카드 높이를 반영

고려한 점

/feeds/popular 응답에 작품 제목이 없어, 임시로 feedContent를 제목처럼 사용하는 방식은 피하고 피드 상세 API를 통해 작품 제목이 보이도록 했습니다.
또한 작품 연결 여부에 따른 지금 뜨는 글 노출 여부와 스포일러 공개 여부는 앱에서 필터링하도록 처리했습니다.

Repository는 상세 정보가 보강된 인기 피드 목록만 반환하도록 하고, 홈에서 한 페이지에 2개씩 묶는 UI 정책은 HomeViewModel에서 처리하도록 책임을 분리했습니다.

📷𝘚𝘤𝘳𝘦𝘦𝘯𝘴𝘩𝘰𝘵

Screenshot_20260528_160429

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

Summary by CodeRabbit

  • New Features

    • 인기 피드에 소설 메타데이터(제목, 이미지, 장르)와 공개 여부가 포함되어 더 풍부한 정보 제공.
  • UI/UX 개선

    • 홈 인기 피드 슬롯이 3→2로 축소되고 카드 레이아웃 및 높이가 조정됨.
    • 썸네일 로딩 품질·장르 오버레이·제목 길이 제한·스포일러 표시가 개선되어 가독성 향상.
  • Bug Fixes

    • 서버 응답의 null/빈 값 기본 처리 및 불완전한 항목 필터링으로 데이터 안정성 강화.

devfeijoa added 4 commits May 26, 2026 13:04
- 작품 연결이 되어있지 않는 글을 뜨지 않게 하기 위해 null 허용으로 전환
- 지금 뜨는 글 피드 슬롯 구성을 3개에서 2개로 변경
- 피드 상세 정보(제목, 썸네일, 장르) 표시를 위한 UI 레이아웃 대폭 수정
- `HomeViewModel`에서 피드 상세 정보를 함께 조회하도록 데이터 가공 로직 추가
- `PopularFeedsViewHolder`에서 썸네일(Coil 사용) 및 제목 생략 처리 등 바인딩 로직 고도화
- `FeedRepository`에 단일 피드 조회(`fetchFeed`) 메서드 추가
- `PopularFeedsAdapter`의 리스트 비교(`DiffUtil`) 로직 수정
- `HomeViewModel`에 있던 인기 피드 가공 로직(`toHomePopularFeeds`)을 `FeedRepository`의 `fetchHomePopularFeeds` 메서드로 이관
- `FeedRepository`에서 인기 피드 목록 조회 시 각 피드의 상세 정보를 병렬로 호출하여 데이터(내용, 스포일러 여부, 작품 정보 등)를 보충하도록 수정
- 공개 상태이며 작품 제목과 이미지가 유효한 피드만 필터링하고 페이지 사이즈(2개)에 맞춰 청킹(Chunk) 처리하는 로직 추가
- `HomeViewModel`의 데이터 로딩 로직을 `runCatching`과 `async/await`을 활용해 예외 처리 및 가독성 개선
- 공통 에러 핸들링을 위한 `handleFailureState` 메서드 추출 및 적용
@devfeijoa devfeijoa requested review from Sadturtleman, m6z1 and s9hn May 27, 2026 02:37
@devfeijoa devfeijoa self-assigned this May 27, 2026
@devfeijoa devfeijoa added 🍯 [FEAT] 새로운 기능을 개발합니다. [👸 공주 은영] labels May 27, 2026
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6fd5a303-f251-4f3d-87db-d2fd73eefc00

📥 Commits

Reviewing files that changed from the base of the PR and between b944668 and f229019.

📒 Files selected for processing (1)
  • app/src/main/res/layout/item_popular_feed_slot.xml
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/res/layout/item_popular_feed_slot.xml

워크스루

API/엔티티 확장, DTO→Entity 매핑 기본값 적용, 저장소의 인기 피드 상세 병렬 조회 추가, 뷰모델 동시성 리팩터링, 2-슬롯 UI 및 레이아웃·이미지 로딩 변경을 포함한 홈 인기 피드 기능 전체 경로 변경.

변경 사항

홈 화면 지금 뜨는 글 기능 구현

Layer / File(s) 요약
API 응답 스키마 및 데이터 모델 확장
app/src/main/java/.../PopularFeedsResponseDto.kt, app/src/main/java/.../PopularFeedsEntity.kt
DTO의 feedContent를 nullable로 변경하고 isPublic, title, novelTitle, novelImage, novelThumbnailImage 등 optional 필드를 추가. Entity에 isPublic, novelTitle, novelImage, novelGenre 필드 추가.
매핑 로직 및 저장소 병렬 상세 조회
app/src/main/java/.../FeedMapper.kt, app/src/main/java/.../FeedRepository.kt
Mapper에서 null/빈값에 대한 기본값(orEmpty(), false) 및 대체값을 적용. Repository에 fetchPopularFeedsWithDetails()를 추가하여 인기 피드 목록 기준으로 상세를 async 병렬 조회·병합·필터링함.
뷰모델 동시성 및 상태 관리
app/src/main/java/.../HomeViewModel.kt
fetchUserHomeData·fetchGuestDatacoroutineScope+async+runCatching 패턴으로 리팩터링, 공통 handleFailureState() 추가, HOME_POPULAR_FEED_PAGE_SIZE = 2 상수 도입 및 인기 피드 chunk 처리 변경.
어댑터/뷰홀더 렌더링 및 레이아웃 조정
app/src/main/java/.../PopularFeedsAdapter.kt, app/src/main/java/.../PopularFeedsViewHolder.kt, app/src/main/res/layout/fragment_home.xml, app/src/main/res/layout/item_popular_feed.xml, app/src/main/res/layout/item_popular_feed_slot.xml
Adapter의 areItemsTheSame을 전체 feedId 시퀀스 비교로 변경. ViewHolder를 3→2 슬롯으로 축소하고 제목 ellipsize, 스포일러 처리, Coil 기반 썸네일(라운딩/에러 처리), 장르 오버레이 표시 및 toImageUrl()/ellipsizeByLength() 헬퍼 추가. 레이아웃 높이·구성 재조정.

Sequence Diagram(s)

sequenceDiagram
  participant HomeViewModel
  participant FeedRepository
  participant RemoteDataSource
  participant FeedMapper
  HomeViewModel->>FeedRepository: fetchPopularFeedsWithDetails()
  FeedRepository->>RemoteDataSource: fetchPopularFeeds()
  RemoteDataSource-->>FeedRepository: popularFeedsDto
  FeedRepository->>FeedRepository: coroutineScope { async per feed -> fetchFeedDetail(feedId) }
  FeedRepository->>RemoteDataSource: fetchFeedDetail(feedId) (concurrent)
  RemoteDataSource-->>FeedRepository: feedDetailDto (or null on failure)
  FeedRepository->>FeedMapper: toData(mergedDto)
  FeedMapper-->>FeedRepository: PopularFeedsEntity
  FeedRepository-->>HomeViewModel: List<PopularFeedEntity> (filtered)
Loading

예상 코드 리뷰 시간

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Team-WSS/WSS-Android#871: HomeViewModel의 코루틴/비동기 호출 방식 변경과 연관된 변경사항을 포함합니다.

제안 검토자

  • s9hn
  • m6z1
  • Sadturtleman

"나는 토끼, 깡충이며 말하네,
DTO를 다듬고 상세를 모으고,
병렬로 달려 리스트를 완성해,
두 칸에 담긴 썸네일 반짝이면,
홈 화면에 이야기 한 줌 더해지네."

🚥 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의 주요 변경사항인 홈 화면 '지금 뜨는 글' 컴포넌트 변경을 정확하게 반영하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿을 따르고 이슈 번호, 작업 설명, 스크린샷, 리뷰어 섹션을 모두 포함하고 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 이슈 #881의 요구사항(2개씩 노출, 피드 상세 보강, 필터링, 스포일러 처리, 장르 표시 등)을 모두 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 홈 화면 '지금 뜨는 글' 컴포넌트 개선이라는 범위 내에 있으며, 관련 없는 기능 추가는 없습니다.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/881

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
app/src/main/res/layout/item_popular_feed_slot.xml (2)

64-64: 💤 Low value

썸네일 marginStart가 의도한 간격인지 확인하세요.

Line 64의 android:layout_marginStart="20dp"FrameLayout에 적용되어 있지만, 제목/본문 텍스트와 썸네일 사이의 간격을 제어합니다. 만약 제목을 제약 기반 레이아웃(0dp)으로 변경한다면, 제목의 marginEnd로 이 간격을 관리하는 것이 더 명확합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/res/layout/item_popular_feed_slot.xml` at line 64, 썸네일의 간격 제어가
현재 FrameLayout의 android:layout_marginStart="20dp"에 의해 이뤄지고 있는데, 제목(TextView 등)이
제약 기반으로 변경되어 width=0dp로 동작할 경우 간격 관리는 제목의 marginEnd로 하는 것이 명확합니다;
item_popular_feed_slot.xml에서 썸네일을 감싼 FrameLayout(썸네일 뷰)에서 layout_marginStart를
제거하고 대신 제목을 정의한 TextView(혹은 제목 관련 뷰)의 android:layout_marginEnd="20dp"로 동일한 간격을
적용하도록 변경하세요.

18-18: ⚡ Quick win

고정 너비(195dp) 대신 제약 기반 레이아웃 사용을 고려하세요.

제목, 본문, 스포일러 텍스트에 하드코딩된 195dp 너비는 다양한 화면 크기에서 반응형으로 동작하지 않습니다. 0dp(match_constraint)와 layout_constraintEnd_toStartOf를 사용하면 썸네일과의 간격을 유지하면서 화면 크기에 맞게 조정됩니다.

♻️ 제약 기반 레이아웃 제안
     <TextView
         android:id="@+id/tv_popular_feed_title"
-        android:layout_width="195dp"
+        android:layout_width="0dp"
+        android:layout_marginEnd="20dp"
         android:layout_height="wrap_content"
         android:ellipsize="end"
         android:maxLines="1"
         android:textAppearance="`@style/title3`"
         android:textColor="`@color/black`"
         app:layout_constraintEnd_toStartOf="`@id/fl_popular_feed_thumbnail`"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintHorizontal_bias="0"
         tools:text="피폐 역하렘 남주들의 막내 처제가..." />
 
     <TextView
         android:id="@+id/tv_popular_feed_content"
-        android:layout_width="195dp"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginTop="4dp"
         android:ellipsize="end"
         android:maxLines="3"
         android:textAppearance="`@style/body5`"
         android:textColor="`@color/black`"
         app:layout_constraintEnd_toEndOf="`@id/tv_popular_feed_title`"
         app:layout_constraintStart_toStartOf="`@id/tv_popular_feed_title`"
         app:layout_constraintTop_toBottomOf="`@id/tv_popular_feed_title`"
         tools:text="이름이 나여주입니다ㅋㅋㅋ읽던 소설이 세계멸망엔딩나서 댓글달았다가 그 세계의 본인에게 빙의하게 되었는데 S급 힐..." />
 
     <TextView
         android:id="@+id/tv_popular_feed_content_spoiler"
-        android:layout_width="195dp"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginTop="8dp"
         android:ellipsize="end"
         android:maxLines="1"
         android:text="`@string/home_popular_feed_spoiler`"
         android:textAppearance="`@style/body5`"
         android:textColor="`@color/secondary_100_FF675D`"
         android:visibility="gone"
         app:layout_constraintEnd_toEndOf="`@id/tv_popular_feed_title`"
         app:layout_constraintStart_toStartOf="`@id/tv_popular_feed_title`"
         app:layout_constraintTop_toBottomOf="`@id/tv_popular_feed_title`"
         tools:visibility="visible" />

참고: 제목에서 layout_constraintHorizontal_bias="0"도 함께 제거했습니다(start 제약만 있을 때 불필요).

Also applies to: 32-32, 46-46

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/res/layout/item_popular_feed_slot.xml` at line 18, Replace the
fixed width (android:layout_width="195dp") on the feed slot text views with a
constraint-based width so the items are responsive: set
android:layout_width="0dp" (match_constraint) for the title/body/spoiler
TextViews and add a layout_constraintEnd_toStartOf pointing to the thumbnail
ImageView (and keep their start constraint to the parent or other anchor), and
remove any unnecessary layout_constraintHorizontal_bias="0" on the title; apply
the same change for the other occurrences (the identical fixed-width attributes
at the other two locations noted in the comment).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/com/into/websoso/data/mapper/FeedMapper.kt`:
- Line 118: The mapping in FeedMapper (the line setting isPublic = feed.isPublic
?: true) uses a default of true which may expose private content; change the
default to false so that when feed.isPublic is null it is treated as non-public.
Locate the mapping method in FeedMapper (the function that constructs the mapped
Feed/DTO and assigns isPublic) and replace the null-coalescing default from true
to false, ensuring all callers still expect a non-null Boolean afterward.

In `@app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt`:
- Around line 147-151: The success-state updates using _uiState.value =
uiState.value?.copy(... popularNovels = popularNovels.popularNovels,
popularFeeds = popularFeeds) (and the similar update at the second success
branch around the other copy at lines noted) do not reset the error flag; modify
both uiState.value?.copy calls to include error = false so a prior error state
is cleared when successful data arrives (update both occurrences where
popularNovels/popularFeeds are assigned).

In `@app/src/main/res/layout/item_popular_feed.xml`:
- Line 36: slot2의 top 제약(layout_constraintTop_toBottomOf)이 현재
`@id/item_popular_fees_slot1로` 되어 있어 divider_1(`@id/divider_1`)이 slot1 바로 아래로 배치된
설정과 충돌합니다; slot2의 top 제약을 divider_1의 아래로 변경하여 중첩을 제거하세요 — 즉
item_popular_feed.xml에서 slot2의 layout_constraintTop_toBottomOf 속성값을
`@id/item_popular_divider_1`(또는 실제 divider_1 ID)로 바꿔 divider_1과 slot1 사이의 순서를
보장하도록 수정하세요.

---

Nitpick comments:
In `@app/src/main/res/layout/item_popular_feed_slot.xml`:
- Line 64: 썸네일의 간격 제어가 현재 FrameLayout의 android:layout_marginStart="20dp"에 의해
이뤄지고 있는데, 제목(TextView 등)이 제약 기반으로 변경되어 width=0dp로 동작할 경우 간격 관리는 제목의 marginEnd로
하는 것이 명확합니다; item_popular_feed_slot.xml에서 썸네일을 감싼 FrameLayout(썸네일 뷰)에서
layout_marginStart를 제거하고 대신 제목을 정의한 TextView(혹은 제목 관련 뷰)의
android:layout_marginEnd="20dp"로 동일한 간격을 적용하도록 변경하세요.
- Line 18: Replace the fixed width (android:layout_width="195dp") on the feed
slot text views with a constraint-based width so the items are responsive: set
android:layout_width="0dp" (match_constraint) for the title/body/spoiler
TextViews and add a layout_constraintEnd_toStartOf pointing to the thumbnail
ImageView (and keep their start constraint to the parent or other anchor), and
remove any unnecessary layout_constraintHorizontal_bias="0" on the title; apply
the same change for the other occurrences (the identical fixed-width attributes
at the other two locations noted in the comment).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 992b4eed-8a16-4f50-861f-b60934dfcc8d

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9fd79 and a43ef50.

📒 Files selected for processing (10)
  • app/src/main/java/com/into/websoso/data/mapper/FeedMapper.kt
  • app/src/main/java/com/into/websoso/data/model/PopularFeedsEntity.kt
  • app/src/main/java/com/into/websoso/data/remote/response/PopularFeedsResponseDto.kt
  • app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt
  • app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt
  • app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsAdapter.kt
  • app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsViewHolder.kt
  • app/src/main/res/layout/fragment_home.xml
  • app/src/main/res/layout/item_popular_feed.xml
  • app/src/main/res/layout/item_popular_feed_slot.xml

Comment thread app/src/main/java/com/into/websoso/data/mapper/FeedMapper.kt Outdated
Comment thread app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt
Comment thread app/src/main/res/layout/item_popular_feed.xml Outdated
devfeijoa added 3 commits May 28, 2026 15:37
- `FeedRepository`의 `fetchHomePopularFeeds` 메서드명을 `fetchPopularFeedsWithDetails`로 변경
- `HomeViewModel`에서 변경된 메서드명을 참조하도록 수정 및 반영
- `FeedRepository`에서 수행하던 인기 피드 리스트 chunk(페이징) 처리를 `HomeViewModel`로 이동
- `FeedRepository.fetchPopularFeedsWithDetails`의 반환 타입을 `List<List<...>>`에서 `List<...>`로 변경
- `HomeViewModel`에 `HOME_POPULAR_FEED_PAGE_SIZE` 상수 추가 및 UI 상태 업데이트 시 데이터 가공 로직 반영
- `FeedMapper`에서 `isPublic` 필드의 기본값을 `true`에서 `false`로 변경

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt (1)

46-61: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

상세 조회 전체 실패를 성공으로 삼키지 마세요.

여기서 상세 API 예외를 전부 null로 바꾸면, 원본 인기 피드가 있어도 fetchPopularFeedsWithDetails()가 빈 리스트로 정상 반환될 수 있습니다. 그러면 HomeViewModel의 실패 처리 경로가 타지 않아 홈 화면에서 섹션이 조용히 사라집니다. 최소한 원본 목록이 비어 있지 않은데 상세 조회가 전부 실패한 경우에는 예외를 다시 올리거나, 실패 신호를 함께 반환하도록 바꿔주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt` around
lines 46 - 61, The current mapping in fetchPopularFeedsWithDetails() uses async
+ runCatching { feedApi.getFeed(feed.feedId)... }.getOrNull(), which swallows
all exceptions and can silently return an empty list; instead return
success/failure info per item (e.g., Result<Feed> or a sealed wrapper) from each
async so you can detect global failure; after awaitAll examine the collected
results and if the input popular feeds list was non-empty but all detail lookups
failed, rethrow an appropriate exception (or return a failure result) rather
than returning an empty list; reference feedApi.getFeed(feed.feedId) and
fetchPopularFeedsWithDetails() when making the change.
app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt (1)

73-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

CancellationException을 runCatching으로 잡아 error UI로 전환될 수 있습니다.

fetchUserHomeData()/fetchGuestData()async { runCatching { ... } }CancellationException까지 Result로 감싸고, exceptionOrNull() != null이면 handleFailureState()로 가서 error = true를 설정합니다(취소는 취소로 전파되어야 합니다). updateFeed()/updateNovel()도 동일 패턴이라 함께 개선 필요합니다.

수정 방향
+import kotlinx.coroutines.CancellationException
+
+private suspend inline fun <T> suspendResultOf(
+    crossinline block: suspend () -> T,
+): Result<T> =
+    try {
+        Result.success(block())
+    } catch (e: CancellationException) {
+        throw e
+    } catch (t: Throwable) {
+        Result.failure(t)
+    }
+
-                val popularFeedsDeferred =
-                    async { runCatching { feedRepository.fetchPopularFeedsWithDetails() } }
+                val popularFeedsDeferred =
+                    async { suspendResultOf { feedRepository.fetchPopularFeedsWithDetails() } }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt` around
lines 73 - 90, The current async { runCatching { ... } } pattern in
fetchUserHomeData()/fetchGuestData() (and similarly in
updateFeed()/updateNovel()) is wrapping CancellationException into a Result and
causing cancelled coroutines to be treated as failures; change each async block
to explicitly rethrow CancellationException before wrapping other exceptions
(e.g. replace async { runCatching { ... } } with async { try {
Result.success(...) } catch (e: CancellationException) { throw e } catch (t:
Throwable) { Result.failure(t) } } ) so cancellations propagate, and keep the
subsequent failure check (exceptionOrNull) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt`:
- Around line 46-61: The current mapping in fetchPopularFeedsWithDetails() uses
async + runCatching { feedApi.getFeed(feed.feedId)... }.getOrNull(), which
swallows all exceptions and can silently return an empty list; instead return
success/failure info per item (e.g., Result<Feed> or a sealed wrapper) from each
async so you can detect global failure; after awaitAll examine the collected
results and if the input popular feeds list was non-empty but all detail lookups
failed, rethrow an appropriate exception (or return a failure result) rather
than returning an empty list; reference feedApi.getFeed(feed.feedId) and
fetchPopularFeedsWithDetails() when making the change.

In `@app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt`:
- Around line 73-90: The current async { runCatching { ... } } pattern in
fetchUserHomeData()/fetchGuestData() (and similarly in
updateFeed()/updateNovel()) is wrapping CancellationException into a Result and
causing cancelled coroutines to be treated as failures; change each async block
to explicitly rethrow CancellationException before wrapping other exceptions
(e.g. replace async { runCatching { ... } } with async { try {
Result.success(...) } catch (e: CancellationException) { throw e } catch (t:
Throwable) { Result.failure(t) } } ) so cancellations propagate, and keep the
subsequent failure check (exceptionOrNull) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8110d88b-2f7d-4aa6-9c6c-d1259f68f5d9

📥 Commits

Reviewing files that changed from the base of the PR and between a43ef50 and d3f492d.

📒 Files selected for processing (2)
  • app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt
  • app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt

devfeijoa added 2 commits May 28, 2026 15:56
- 인기 피드 슬롯의 높이를 고정값(122dp)에서 `0dp`로 변경하여 영역을 가변적으로 차지하도록 수정
- 구분선(divider)을 중앙에 배치하고, 이를 기준으로 슬롯 1과 2가 상하로 균등하게 배치되도록 제약 조건 조정
- `HomeViewModel`에서 인기 작품 및 인기 피드 데이터 로드 성공 시 `error` 상태를 `false`로 변경하도록 수정

@Sadturtleman Sadturtleman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고하셨습니다!

@m6z1 m6z1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

작품 장르에 따라 썸네일 우측 하단에 세모난 박스도 작품 장르따라 색상이 바껴야 할 것 같아요!
확인 부탁드려욥

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

디자인 쪽 패딩 확인해주세요! 이미지랑 text 값이 동일한 height 는 아닌 것 같아용

@devfeijoa devfeijoa Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

이것도 제가 놓친 부분이네요 ! 피그마 확인하여 반영하였습니다! 감사합니다 👍
f229019

devfeijoa added 2 commits June 1, 2026 23:44
- `PopularFeedsEntity`의 `novelGenreImage` 필드를 `novelGenre`로 변경
- `PopularFeedsResponseDto`에서 사용하지 않는 `novelGenreImage` 필드 제거
- `FeedRepository`에서 피드 상세 정보 조회 시 장르 데이터(`novelGenre`)를 할당하고, 유효성 검사 조건에 장르 공백 여부 추가
- `FeedMapper`의 데이터 변환 로직 수정 (장르 초기값 설정)
- `item_popular_feed_slot.xml`의 썸네일 영역을 `FrameLayout`에서 `MaterialCardView`로 변경하여 모서리 곡률(8dp) 적용
- 장르 표시 로직을 원격 이미지 로드 방식에서 로컬 드로어블 리소스(`FeedDetailGenre`) 매핑 방식으로 변경
- 불필요한 장르 프레임 이미지(`iv_popular_feed_genre_frame`) 및 관련 SvgDecoder 의존성 제거
- 제목 `TextView`의 제약 조건 위치 조정 및 레이아웃 최적화

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/res/layout/item_popular_feed.xml`:
- Around line 13-17: The layout is forcing slot1/slot2 to each take half the
parent because the divider is constrained to the parent's center; when there is
only one item the ViewHolder leaves slot2 INVISIBLE which still consumes space.
Update PopularFeedsViewHolder to set slot2 visibility to GONE (not INVISIBLE)
when only one item and also set the divider to GONE; additionally adjust the
constraints in item_popular_feed.xml so the divider is constrained between slot1
and slot2 (or slot1 bottom to parent when divider is GONE) instead of fixed to
parent center—look for IDs slot1, slot2, view_popular_feed_divider_1 and the
PopularFeedsViewHolder logic that toggles visibility and change it accordingly
so a single item can expand to full height.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 748706f1-19e4-41ba-9116-37a24e9e8eb5

📥 Commits

Reviewing files that changed from the base of the PR and between d3f492d and b944668.

📒 Files selected for processing (8)
  • app/src/main/java/com/into/websoso/data/mapper/FeedMapper.kt
  • app/src/main/java/com/into/websoso/data/model/PopularFeedsEntity.kt
  • app/src/main/java/com/into/websoso/data/remote/response/PopularFeedsResponseDto.kt
  • app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt
  • app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt
  • app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsViewHolder.kt
  • app/src/main/res/layout/item_popular_feed.xml
  • app/src/main/res/layout/item_popular_feed_slot.xml
💤 Files with no reviewable changes (1)
  • app/src/main/java/com/into/websoso/data/remote/response/PopularFeedsResponseDto.kt
🚧 Files skipped from review as they are similar to previous changes (5)
  • app/src/main/java/com/into/websoso/data/model/PopularFeedsEntity.kt
  • app/src/main/java/com/into/websoso/data/repository/FeedRepository.kt
  • app/src/main/res/layout/item_popular_feed_slot.xml
  • app/src/main/java/com/into/websoso/ui/main/home/adpater/PopularFeedsViewHolder.kt
  • app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt

Comment on lines +13 to +17
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/view_popular_feed_divider_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

한 개 아이템 페이지에서 카드가 반 높이로 잘립니다.

PopularFeedsViewHolder에서 아이템이 1개면 divider만 GONE 처리하고 slot2INVISIBLE로 남기는데, 지금 제약은 divider를 항상 부모 중앙에 두고 slot1/slot2가 그 기준으로 반씩 나뉘도록 고정돼 있습니다. 그래서 마지막 페이지가 1개일 때도 첫 카드가 상단 절반만 차지하고 하단은 빈 터치 불가 영역으로 남습니다.

Also applies to: 21-27, 33-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/res/layout/item_popular_feed.xml` around lines 13 - 17, The
layout is forcing slot1/slot2 to each take half the parent because the divider
is constrained to the parent's center; when there is only one item the
ViewHolder leaves slot2 INVISIBLE which still consumes space. Update
PopularFeedsViewHolder to set slot2 visibility to GONE (not INVISIBLE) when only
one item and also set the divider to GONE; additionally adjust the constraints
in item_popular_feed.xml so the divider is constrained between slot1 and slot2
(or slot1 bottom to parent when divider is GONE) instead of fixed to parent
center—look for IDs slot1, slot2, view_popular_feed_divider_1 and the
PopularFeedsViewHolder logic that toggles visibility and change it accordingly
so a single item can expand to full height.

@devfeijoa

devfeijoa commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

작품 장르에 따라 썸네일 우측 하단에 세모난 박스도 작품 장르따라 색상이 바껴야 할 것 같아요!
확인 부탁드려욥

여기서는 장르 뱃지가 세모난 박스따라 다르게 나오는지 몰랐네요..! 확인하고 피드 상세 박스처럼 바꿨습니다!
b944668

- 인기 피드 제목(`tv_popular_feed_title`) 상단 여백(7dp) 추가
@devfeijoa devfeijoa merged commit c3062f1 into develop Jun 3, 2026
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 16, 2026
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: 홈 화면 '지금 뜨는 글'

3 participants