Skip to content

[Refactor] 썸네일 디코드 크기 티어화 및 PhotoNavGrid 제네릭화 (#70) - #71

Merged
ddodle merged 3 commits into
mainfrom
refactor/70-thumbnail-tier-grid-generics
Aug 29, 2026
Merged

ddodle merged 3 commits into
mainfrom
refactor/70-thumbnail-tier-grid-generics

Conversation

@ddodle

@ddodle ddodle commented Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

Close #70

✨ PR 유형

어떤 변경 사항이 있나요??

  • 새로운 기능 추가
  • 버그 수정
  • 사용자 UI 디자인 변경 및 추가
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

🛠️ 작업내용

1. 썸네일 디코드 크기를 ThumbnailTier로 통합

Nuke는 resize processor의 크기를 캐시 키(identifier)에 포함한다. 같은 URL을 화면마다 다른 크기로 요청하면 캐시 엔트리가 각각 따로 쌓인다. 호출부 세 곳에 흩어져 있던 크기를 enum 두 케이스로 못박아 파편화의 상한을 잡았다.

티어 크기(pt) 사용처
.grid 150 × 150 홈 · 민감 사진 · 검색 결과 · 앨범 상세 3열 타일
.card 200 × 160 앨범 카드 커버 + 앨범 상세 배너 스트립 공용

앨범 상세 배너가 쓰던 390×140 전용 크기를 없애고 .card로 합쳤다. 앨범 목록에서 이미 디코드해둔 커버 비트맵을 상세 배너가 그대로 재사용한다.

두 뷰가 ImageRequest를 직접 조립하지 않게 되어 import Nuke도 걷어냈다(NukeUI만 남음).

2. PhotoNavGrid 항목 타입 제네릭화

Core/UIComponents의 공용 그리드가 Features/Home/Domain의 Photo를 직접 받고 있었다. 의존성 규칙은 Feature → Core 단방향인데 방향이 역전된 상태다.

// before — Core가 Home Feature의 Photo를 안다
struct PhotoNavGrid: View { let photos: [Photo] }

// after — 항목 타입은 제네릭, URL 추출은 호출부가 키패스로
struct PhotoNavGrid<Item: Identifiable & Hashable>: View {
    let items: [Item]
    let imageUrl: (Item) -> URL
}

줌 전환 식별자도 photo.photoId → item.id로 바꿔 Core가 어떤 도메인 모델도 알지 않게 했다. 호출부 3곳(홈 그리드 · 앨범 상세 · 검색 결과) 갱신.

📋 추후 진행 상황

이 PR이 머지된 뒤 에러 처리 계층 통합을 별도 이슈/PR로 올린다. AppError · Loadable<T> · ErrorHandler를 도입해 "결과 없음"과 "불러오기 실패"가 같은 화면으로 보이는 문제, ViewModel마다 errorMessage = error.localizedDescription을 반복하는 문제를 정리하는 작업이다. 그다음으로 로컬 목 서버 스크립트 커밋.

📌 리뷰 포인트

  • .card 티어 공유의 트레이드오프 — 사진이 1~2장뿐인 앨범은 배너 스트립이 티어 폭(200pt)보다 넓어져 약간 흐려진다. 스크림과 타이틀이 덮는 배경이라 캐시 공유의 이득이 더 크다고 판단했는데, 이 판단이 타당한지
  • 티어 크기 여유분 — .grid 150pt는 iPhone 세로 기준 실제 타일 폭 약 130pt 대비 여유가 있다. upscale이 기본 false라 원본이 티어보다 작으면 확대하지 않는다
  • PhotoNavGrid가 imageUrl 클로저를 받는 방식 — 호출부는 \.imageUrl 키패스만 넘기므로 body 평가마다 클로저가 새로 만들어지지 않는다

✅ Checklist

PR이 다음 요구 사항을 충족하는지 확인해주세요!!!

Summary by CodeRabbit

  • 개선 사항
    • 사진 그리드와 앨범 카드의 썸네일 로딩 및 표시 품질을 일관되게 개선했습니다.
    • 다양한 사진 데이터에 사진 그리드를 재사용할 수 있도록 구조를 개선했습니다.
    • 썸네일 크기를 용도별로 최적화해 이미지 로딩과 캐시 효율을 향상했습니다.

ddodle added 3 commits August 29, 2026 16:43
Nuke는 resize processor의 크기를 캐시 키에 포함하므로, 같은 URL을 화면마다
다른 크기로 요청하면 캐시 엔트리가 각각 따로 쌓인다. 호출부에 흩어져 있던
디코드 크기를 enum 두 케이스로 못박아 파편화의 상한을 잡는다.

- .grid (150×150) — 3열 정사각 타일
- .card (200×160) — 앨범 카드 커버 + 앨범 상세 배너 공용

PhotoGridTile이 첫 사용처. 크기를 티어가 소유하므로 타일은 ImageRequest를
직접 조립하지 않고 Nuke 의존도 걷어낸다.
앨범 상세 배너가 쓰던 390×140 전용 크기를 없애고 앨범 카드 커버와 같은
.card 티어로 합친다. 크기가 캐시 키에 들어가므로, 목록에서 이미 디코드해둔
커버 비트맵을 상세 배너가 그대로 재사용한다.

사진이 1~2장뿐인 앨범은 스트립이 티어 폭보다 넓어져 흐려지지만, 스크림과
타이틀이 덮는 배경이라 캐시 공유의 이득이 더 크다고 보고 감수한다.

두 뷰 모두 ImageRequest를 직접 조립하지 않게 되어 Nuke import를 걷어낸다.
Core/UIComponents의 공용 그리드가 Features/Home의 도메인 모델(Photo)을 직접
받고 있었다. 의존성 규칙은 Feature → Core 단방향인데 방향이 역전된 상태로,
Step 4 멀티모듈 분리에서 그대로 Core ↔ Feature 순환 의존이 된다.

항목 타입을 Item: Identifiable & Hashable로 열고, 썸네일 URL을 꺼내는 방법은
호출부가 키패스(\.imageUrl)로 넘긴다. 줌 전환 식별자도 photoId 대신 item.id를
쓰므로 Core는 어떤 도메인 모델도 알지 않는다.

호출부 3곳(홈 그리드, 앨범 상세, 검색 결과) 갱신.
@coderabbitai

coderabbitai Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 04ddabd4-ab77-48a8-873f-321c743dbe92

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1acb5 and 136fda2.

📒 Files selected for processing (6)
  • Rephoto_iOS/Core/UIComponents/PhotoGridTile.swift
  • Rephoto_iOS/Core/UIComponents/PhotoNavGrid.swift
  • Rephoto_iOS/Core/UIComponents/ThumbnailTier.swift
  • Rephoto_iOS/Features/Home/Presentation/Views/HomeView.swift
  • Rephoto_iOS/Features/Search/Presentation/Views/AlbumDetailView.swift
  • Rephoto_iOS/Features/Search/Presentation/Views/SearchView.swift

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

썸네일 요청을 grid와 card 티어로 통합했습니다. PhotoNavGrid를 제네릭 컴포넌트로 변경했습니다. 홈과 검색 화면의 호출부를 새 인터페이스에 맞게 갱신했습니다.

Changes

썸네일 및 그리드 리팩터링

Layer / File(s) Summary
공유 썸네일 티어 적용
Rephoto_iOS/Core/UIComponents/ThumbnailTier.swift, Rephoto_iOS/Core/UIComponents/PhotoGridTile.swift, Rephoto_iOS/Features/Search/Presentation/Views/{AlbumDetailView,SearchView}.swift
ThumbnailTier가 grid 150×150과 card 200×160 크기의 ImageRequest를 생성합니다. 그리드 타일, 앨범 카드, 배너가 공유 티어를 사용합니다. 직접 구성한 Nuke 요청과 사용하지 않는 import를 제거했습니다.
제네릭 PhotoNavGrid 통합
Rephoto_iOS/Core/UIComponents/PhotoNavGrid.swift, Rephoto_iOS/Features/Home/Presentation/Views/HomeView.swift, Rephoto_iOS/Features/Search/Presentation/Views/{AlbumDetailView,SearchView}.swift
PhotoNavGrid가 Item: Identifiable & Hashable과 imageUrl 추출 클로저를 받습니다. 홈과 검색 화면은 items 및 imageUrl: \.imageUrl을 전달합니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 136fd

This change centralizes thumbnail sizing and makes the photo grid reusable without changing the existing image-loading path or introducing new production dependencies. No actionable merge-blocking risk remains after normal checks and review.

Poem

토끼가 새 티어를 깡충 세웠네
그리드와 카드가 크기를 맞췄네
사진 길은 제네릭으로 열리고
URL은 키패스로 또렷이 흐르고
캐시 조각은 한곳에 모였네
당근처럼 깔끔한 변경이네

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 썸네일 디코드 크기 티어화와 PhotoNavGrid 제네릭화를 모두 정확하게 요약합니다.
Description check ✅ Passed PR 설명은 템플릿의 유형, 작업내용, 추후 진행 상황, 리뷰 포인트, 체크리스트를 모두 포함합니다. 변경 목적과 주요 구현 내용도 구체적으로 설명합니다.
Linked Issues check ✅ Passed PR은 [#70]의 모든 주요 목표를 충족합니다. ThumbnailTier로 디코드 크기를 두 티어로 통합했고, 앨범 카드와 상세 배너가 .card 티어를 공유하도록 변경했습니다. PhotoNavGrid도 Item: Identifiable & Hashable 제네릭으로 변경하고 세 호출부를 갱신했습니다.
Out of Scope Changes check ✅ Passed 변경 사항은 [#70]의 썸네일 티어 통합, 캐시 공유, PhotoNavGrid 제네릭화 및 호출부 갱신 범위에 포함됩니다. 관련 없는 코드 변경은 확인되지 않습니다.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 6 files.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/70-thumbnail-tier-grid-generics

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.

@ddodle ddodle self-assigned this Aug 29, 2026
@ddodle
ddodle merged commit a19deca into main Aug 29, 2026
2 checks passed
@ddodle
ddodle deleted the refactor/70-thumbnail-tier-grid-generics branch August 29, 2026 07:55
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.

♻️ Refactor: 썸네일 디코드 크기 티어화 및 PhotoNavGrid 제네릭화

1 participant