Skip to content

히스토리 화면 view 구현#100

Merged
HamBeomJoon merged 16 commits intodevelopfrom
feat/#98-history-view
Apr 16, 2026
Merged

히스토리 화면 view 구현#100
HamBeomJoon merged 16 commits intodevelopfrom
feat/#98-history-view

Conversation

@HamBeomJoon
Copy link
Copy Markdown
Contributor

@HamBeomJoon HamBeomJoon commented Apr 13, 2026

📌 작업 내용

  • 히스토리 화면 기본 UI를 구성하고, 준비 중인 발표 / 완료한 발표 탭 구조를 추가했습니다.
  • 히스토리 상단 헤더와 탭, 발표 리스트, 빈 상태 UI를 각각 분리된 컴포넌트로 정리했습니다.
  • 히스토리 카드에 발표 제목, 날짜, 디데이, 카테고리/목적/스타일/청중 정보를 표시하도록 구성했습니다. -> Domain Model로 생성
  • 빈 상태 일러스트와 안내 문구, 발표 추가 버튼 UI를 추가했습니다.
  • 히스토리 화면의 로딩 상태를 빈 상태와 분리해, 데이터 로드 전 empty 문구와 버튼이 잘못 노출되지 않도록 수정했습니다.
  • 히스토리 아이템에 status 값을 추가해 준비중 발표와 완료 발표를 구분할 수 있도록 정리했습니다.
  • 히스토리 아이템 클릭 시 준비중/완료에 따라 분기할 수 있는 구조를 먼저 반영했고, 실제 다음 화면 연결은 추후 발표분석 페이지 모듈 추가 시 붙일 수 있도록 정리했습니다.

  • core:ui모듈에 Empty, Loading, Error를 나타낼 수 있는 StatusView를 추가했습니다.
  • historyUiModel과 도메인 모델, Mapper를 추가했습니다.

🧩 관련 이슈


📸 스크린샷

준비 중인 발표(빈 화면) 완료한 발표(빈 화면)
Screenshot_1776093716 Screenshot_1776093758
준비 중인 발표 완료한 발표
Screenshot_1776093804 Screenshot_1776093802
EmptyView ErrorView
스크린샷 2026-04-17 01 23 07 스크린샷 2026-04-17 01 23 12

📢 논의하고 싶은 내용

D-day 남은 발표, D-day 지난 발표카드 클릭시 넘어가는 페이지가 달라 status 값을 uiModel에 넣고 분기처리하려고 합니다.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 프레젠테이션 히스토리를 준비 중인 것과 완료된 것으로 분류하여 표시하는 새로운 히스토리 화면 추가
    • 각 프레젠테이션 카드에 D-Day, 날짜, 제목, 카테고리 등의 정보를 표시
    • 빈 상태를 위한 일러스트레이션 및 애니메이션 추가

* feat: History 피처 MVI 컨트랙트 정의 및 UI 상태 모델 추가

MVI(Model-View-Intent) 패턴 적용을 위해 `HistoryUiState`, `HistoryUiIntent`, `HistoryUiEffect`를 추가하고 관련 UI 메시지 모델을 정의했습니다.

*   `HistoryUiState`: `Loading`, `LoadFailed` 상태 정의
*   `HistoryUiIntent`: `FetchData` 의도 추가
*   `HistoryUiEffect`: `ShowMessage`를 통한 일회성 이벤트(Side Effect) 처리 구조 추가
*   `HistoryUiMessage`: 데이터 로드 실패 등 UI 알림을 위한 열거형 정의

* refactor: HistoryViewModel의 BaseViewModel 상속 및 구조 변경

*   `ViewModel`을 `BaseViewModel`로 교체하여 MVI 기반 상태 관리 로직 적용
*   `onIntent` 메서드 오버라이드 및 기본 구현 (TODO)

* feat: History 피처 문자열 리소스 추가

*   데이터 로드 실패 시 표시할 국문 메시지 리소스 추가 (`feature_history_impl_fetch_data_failed`)

* refactor: HistoryScreen 리팩터링 및 Hilt 연동

*   `HistoryViewModel`을 주입받는 내부 `HistoryScreen` 컴포저블 추가
*   기존 UI 상태 파일을 `contract` 패키지로 이동 및 정리
히스토리 피처의 기본 화면 구조를 설계하고, 발표 목록 및 탭 전환을 위한 UI 컴포넌트를 구현했습니다.

* **화면 및 네비게이션 구현**:
    * `HistoryScreen`: `HorizontalPager`를 활용하여 '준비 중인 발표'와 '완료한 발표' 탭 간의 화면 전환 구조 구현
    * `HistoryViewModel`: 데이터 페칭을 위한 `FetchData` 인텐트 처리 로직 및 MVI 기반 구조 적용
    * `LocalSnackbarHostState`를 통한 데이터 로드 실패 시 에러 메시지 표시 로직 추가

* **UI 컴포넌트 추가**:
    * `HistoryHeadSection`: 상단 앱바와 `PrezelTabs`를 포함하는 헤더 섹션 구현
    * `HistoryItemList`: `LazyColumn`을 사용하여 발표 아이템(`PresentationItem`) 리스트 표시
    * `HistoryPresentationCard`: 발표 제목, D-Day, 날짜 및 관련 키워드(Chip)를 포함하는 카드 UI 구현
    * `HistoryChip`: 강조 여부에 따라 스타일(Filled/Outlined)이 적용된 커스텀 칩 컴포넌트 추가

* **데이터 모델 및 리소스**:
    * `PresentationItem`, `HistoryChipUiModel` 등 화면 구현에 필요한 데이터 모델 정의
    * 히스토리 타이틀 및 에러 메시지 관련 문자열 리소스 추가
    * `kotlinx.collections.immutable` 의존성 추가 및 `persistentListOf` 적용으로 안정성 강화
* refactor: `PresentationItem`을 `HistoryUiModel`로 변경 및 구조 개선

기존 `PresentationItem`을 `HistoryUiModel`로 명칭을 변경하고, 발표 카테고리 관리를 위해 `Category` 필드를 추가했습니다.

*   `PresentationItem.kt` 삭제 및 `HistoryUiModel.kt` 생성
*   `HistoryUiModel` 내 `Category` 타입의 `category` 프로퍼티 추가
*   `feature:history:impl` 모듈에 `core:model` 의존성 추가

* feat: `HistoryUiState` 내 콘텐츠 상태 정의 및 데이터 바인딩

발표 준비 중인 항목과 완료된 항목을 구분하여 관리할 수 있도록 `HistoryUiState`를 개선하고 ViewModel에서 초기 데이터를 주입했습니다.

*   `HistoryUiState.Content` 클래스 추가 (`preparingPresentations`, `completedPresentations` 리스트 포함)
*   `HistoryViewModel` 내 `fetchData`를 통해 더미 데이터 로드 로직 구현
*   `HistoryScreen`에서 `UiState`를 기반으로 페이지 데이터를 생성하는 `toPages()` 확장 함수 추가

* refactor: History 관련 컴포넌트 및 프리뷰 최신화

UI 모델 변경 사항을 관련 컴포넌트에 반영하고 프리뷰 데이터를 실제와 유사하게 수정했습니다.

*   `HistoryItemList` 및 `HistoryPresentationCard`에서 사용하는 모델을 `HistoryUiModel`로 업데이트
*   `HistoryScreenPreview`에서 `HistoryUiState.Content`를 사용하여 실제 화면 구성과 동일하게 프리뷰 구현
*   `HistoryItemList` 내 프리뷰용 더미 데이터에 `Category` 정보 추가
… 매퍼를 추가했습니다.

* **feat: core:model 내 발표 관련 도메인 모델 추가**
    * 발표의 목적(`Purpose`), 스타일(`Style`), 대상(`Audience`)을 정의하는 enum 클래스 추가

* **feat: 히스토리 발표 카드 컴포넌트 및 리소스 추가**
    * `HistoryPresentationCard`: 날짜, 제목, 카테고리 및 메타 정보 칩을 포함하는 카드 UI 구현
    * `HistoryChipLabelMapper`: 도메인 모델을 UI 문자열 리소스 ID로 변환하는 확장 함수 추가
    * `feature:history:impl`에 카테고리, 목적, 스타일, 대상별 국문 문자열 리소스 추가

* **refactor: 히스토리 UI 모델 및 데이터 구조 개선**
    * `HistoryUiModel`에서 자유 형식의 `HistoryChipUiModel` 리스트를 제거하고, `Category`, `Purpose`, `Style`, `Audience`를 직접 보유하도록 구조 변경
    * `HistoryItemList` 및 `HistoryScreen`의 프리뷰 데이터를 신규 모델 구조에 맞춰 업데이트
    * `HistoryViewModel`의 초기 상태 데이터를 상세 모델 기반으로 변경

* **refactor: 히스토리 컴포넌트 구조 분리**
    * `HistoryItemList.kt`에 포함되어 있던 카드 구현부를 `HistoryPresentationCard.kt`로 분리하여 모듈화 및 가독성 개선
* feat: 히스토리 탭 정의 및 문자열 리소스 추가

히스토리 화면에서 사용하는 탭 항목을 리소스화하고 관련 로직을 추가했습니다.
* `historyTabs()` 함수 추가: "준비 중인 발표", "완료한 발표" 탭 이름을 `stringResource`로 관리
* 기존 하드코딩된 `historyTabs` 변수 제거 및 호출부 수정

* feat: HistoryPresentationCard 클릭 기능 추가 및 UI 개선

히스토리 목록의 각 아이템 카드에 클릭 이벤트를 지원하도록 구조를 변경했습니다.
* `HistoryPresentationCard`: `onClick` 파라미터 추가 및 `PrezelTouchArea` 적용
* `HistoryItemList`: `onClickItem` 콜백 추가 및 각 카드에 전달

* refactor: HistoryScreen 내 탭 및 목록 처리 로직 수정

* `HistoryScreen` 및 `HistoryHeadSection`: 신규 `historyTabs()` 함수를 사용하도록 수정
* `HistoryItemList` 호출 시 클릭 리스너 연결 (현재 빈 블록)
* 프리뷰 코드 내 탭 데이터 참조 방식 업데이트
*   **feat: 히스토리 빈 화면 컴포넌트 추가**
    *   `HistoryEmptyContent`: 발표 내역이 없을 때 표시되는 공통 UI 컴포넌트 추가
    *   탭 종류(준비 중/완료)에 따라 서로 다른 안내 문구 및 '발표 추가하기' 버튼 노출 로직 구현
    *   비어있는 상태를 나타내는 신규 이미지 리소스(`feature_history_impl_empty_no_presentation`) 및 문자열 추가

*   **feat: HistoryScreen 내 빈 화면 처리 로직 적용**
    *   각 탭의 아이템 리스트(`items`)가 비어있는 경우 `HistoryEmptyContent`를 표시하도록 분기 로직 추가

*   **feat: 히스토리 발표 추가 버튼 구현**
    *   `HistoryAddPresentationButton`: `PrezelButton`을 활용한 커스텀 버튼 컴포넌트 추가 및 디자인 가이드 반영 (Small size, Outlined type)
* refactor: `HistoryScreen` 컴포넌트 구조 분리 및 가독성 개선

`HistoryScreen` 내부에 혼재되어 있던 UI 로직을 `HistoryContent`, `HistoryPagerContent`로 분리하여 가독성을 높이고 상태에 따른 분기 처리를 명확하게 개선했습니다.

*   `HistoryUiState`에 따른 로딩/콘텐츠 렌더링 분기 추가
*   `HorizontalPager`를 별도의 `HistoryPagerContent` 컴포posable로 추출
*   기존 `toPages` 확장 함수를 제거하고 `HistoryPagerContent` 내부에서 직접 페이지 리스트 정의

* feat: 히스토리 아이템 클릭 처리 로직 추가

히스토리 목록의 아이템 클릭 이벤트를 처리하기 위한 인터페이스를 추가하고 상태별 분기를 정의했습니다.

*   `HistoryUiModel`에 `HistoryPresentationStatus` (PREPARING, COMPLETED) 필드 추가
*   `HistoryScreen` 및 `HistoryItemList`에 `onClickHistoryItem` 콜백 추가
*   클릭 시 아이템의 상태(`status`)에 따른 처리 로직 구조 마련

* refactor: 히스토리 UI 모델 및 관련 컴포넌트 수정

*   `HistoryUiModel`: 프리젠테이션 상태 관리를 위한 `status` 프로퍼티 추가
*   `HistoryPresentationCard`: 내부 칩(Chips) 레이아웃 최적화를 위해 `@OptIn(ExperimentalLayoutApi::class)` 추가
*   `HistoryEmptyContent`: `Image` 컴포넌트에 전달되던 `modifier` 오적용 수정 (`Modifier.size` 직접 사용)
*   `HistoryViewModel` 및 Preview: 신규 필드(`status`) 추가에 따른 더미 데이터 업데이트
`HistoryViewModel`의 `fetchData` 메서드 내에 인라인으로 정의되어 있던 더미 데이터 생성 로직을 별도의 프로퍼티와 함수로 분리하여 가독성을 개선했습니다.

*   `preparingPresentations` 및 `completedPresentations`를 별도의 `private val`로 추출
*   `HistoryUiState.Content` 생성을 담당하는 `createHistoryContentState` 함수 추가
@HamBeomJoon HamBeomJoon self-assigned this Apr 13, 2026
@HamBeomJoon HamBeomJoon requested a review from moondev03 as a code owner April 13, 2026 15:51
@HamBeomJoon HamBeomJoon added the ✨ feat 새로운 기능 추가 또는 기존 기능 확장 label Apr 13, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

📝 Walkthrough

워크스루

히스토리 화면의 본격적인 UI 구현으로, 프리젠테이션 메타데이터를 나타내는 새로운 도메인 모델(Audience, Purpose, Style 열거형)을 추가하고, MVVM 아키텍처 기반의 ViewModel, 상태/의도/이펙트 계약 객체, UI 모델 및 Compose 컴포넌트들을 구현하였습니다.

변경사항

Cohort / File(s) Summary
Core Model Presentation Enums
core/model/.../presentation/Audience.kt, Purpose.kt, Style.kt
프리젠테이션의 청중, 목적, 스타일을 분류하는 세 개의 새로운 열거형 추가
History Presentation Model
core/model/.../presentation/HistoryPresentation.kt
메타데이터(범주, 목적, 스타일, 청중) 및 D-day 계산 로직을 포함하는 히스토리 데이터 클래스 추가
History Feature Contracts
feature/history/impl/.../contract/HistoryUiState.kt, HistoryUiIntent.kt, HistoryUiEffect.kt
UI 상태, 사용자 의도, 사이드 이펙트를 정의하는 sealed 인터페이스 및 메시지 열거형 추가
History Feature UI Models
feature/history/impl/.../model/HistoryUiModel.kt, HistoryPageUiModel.kt, HistoryUiMessage.kt
화면 렌더링을 위한 불변 데이터 클래스 및 페이지 타입 열거형 추가
History Screen & ViewModel
feature/history/impl/.../HistoryScreen.kt, HistoryViewModel.kt
BaseViewModel 상속, intent 처리, 탭 기반 페이지 레이아웃, 스낵바 메시지 표시 기능 구현
History UI Components
feature/history/impl/.../component/HistoryPresentationCard.kt, HistoryItemList.kt, HistoryEmptyContent.kt
카드형 프리젠테이션 항목, 스크롤 가능한 리스트, 빈 상태 뷰 composable 추가
History Resources
feature/history/impl/.../drawable/feature_history_impl_empty_no_presentation.xml, values/strings.xml
빈 상태 벡터 드로어블 및 화면 제목, 탭 레이블, 칩 텍스트, 에러 메시지 등 다국어 문자열 리소스 추가
Core UI Components
core/ui/.../StatusView.kt
상태 표시용 범용 composable(제목, 설명, 시각 요소, 액션 버튼 및 Lottie 애니메이션 지원)
Build Dependencies
feature/history/impl/build.gradle.kts, core/ui/build.gradle.kts, gradle/libs.versions.toml
core-model, immutable collections, datetime 라이브러리 및 Lottie 6.6.7 의존성 추가

관련 가능성 있는 PR

🚥 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 제목이 '히스토리 화면 view 구현'으로 변경 세트의 주요 목표(히스토리 화면 UI 구현)를 명확하게 설명합니다.
Linked Issues check ✅ Passed PR 변경사항이 #98 이슈의 요구사항(히스토리 화면 UI 구현, 탭 구조, 빈 상태 처리, 카드 레이아웃)을 모두 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 히스토리 화면 view 구현과 필요한 지원 모듈(Audience, Purpose, Style 열거형, StatusView, HistoryPresentation 도메인 모델)에 범위 내이므로 범위 외 변경사항이 없습니다.
Description check ✅ Passed PR 설명이 저장소의 템플릿 구조를 따르며 작업 내용, 관련 이슈, 스크린샷, 논의 사항을 모두 포함하고 있습니다.

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


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (1)
Prezel/feature/history/impl/src/main/res/drawable/feature_history_impl_empty_no_presentation.xml (1)

7-20: 빈 상태 아이콘 색상은 리소스로 추출해 두는 편이 유지보수에 유리합니다.
현재 하드코딩 색상 반복으로 다크모드/테마 확장 시 수정 지점이 늘어납니다.

♻️ 제안 변경안
-        android:fillColor="#AFB3BA"
+        android:fillColor="@color/feature_history_impl_empty_illustration"
-        android:fillColor="#AFB3BA"
+        android:fillColor="@color/feature_history_impl_empty_illustration"
-        android:fillColor="#AFB3BA"
+        android:fillColor="@color/feature_history_impl_empty_illustration"
-        android:fillColor="#AFB3BA"
+        android:fillColor="@color/feature_history_impl_empty_illustration"
-        android:fillColor="#AFB3BA"
+        android:fillColor="@color/feature_history_impl_empty_illustration"

추가로 아래처럼 색상 리소스를 정의해 두면 됩니다(파일 외 변경):

<!-- res/values/colors.xml -->
<color name="feature_history_impl_empty_illustration">#AFB3BA</color>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/feature/history/impl/src/main/res/drawable/feature_history_impl_empty_no_presentation.xml`
around lines 7 - 20, Replace the repeated hard-coded color "#AFB3BA" in the
drawable by referencing a color resource: add a color named
feature_history_impl_empty_illustration to your colors.xml and update every
android:fillColor attribute in the drawable (all path elements using
android:fillColor="#AFB3BA") to use
`@color/feature_history_impl_empty_illustration` instead so the icon color is
centralized for theming and dark mode support.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt`:
- Around line 108-117: The Row containing the chips (Row with modifier,
HistoryCategoryChip and three HistoryMetaChip calls) forces all chips on one
line causing truncation on small screens; replace that Row with a wrapping
FlowRow (e.g., androidx.compose.foundation.layout.FlowRow or accompanist
FlowRow) so chips can wrap to new lines, preserve the modifier, horizontal
spacing Arrangement.spacedBy(PrezelTheme.spacing.V8) (or FlowRow's
mainAxisSpacing/crossAxisSpacing equivalents) and verticalAlignment behavior,
and add the necessary import for FlowRow.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`:
- Around line 149-153: The empty-state CTA is currently a no-op because
HistoryEmptyContent is called with an empty lambda for onClickAddPresentation;
fix it by wiring a real callback (or a nullable callback that the caller
provides) into HistoryScreen so the button triggers the intended action, or
explicitly disable the button when no callback is supplied. Locate the
HistoryScreen invocation that builds HistoryEmptyContent (reference
HistoryEmptyContent and its onClickAddPresentation parameter) and either forward
a provided onAddPresentation callback from the parent into HistoryScreen or
change the parameter to accept a nullable (() -> Unit)? and handle
enabling/disabling the CTA accordingly so the button is never a silent no-op.
- Around line 95-97: The tab selection currently waits for
pagerState.animateScrollToPage to finish (called inside the onClickTab lambda),
causing the selected tab/indicator to update late; replace the async animated
call with an immediate pagerState.scrollToPage call (or implement the
PrezelTabsPager pattern: detect currentPage and only call animateScrollToPage
for adjacent pages) and remove the scope.launch wrapper so the selection updates
synchronously in PrezelTabs when onClickTab is invoked; update usages of
pagerState.animateScrollToPage in the onClickTab lambda accordingly to use
pagerState.scrollToPage or the adjacent-animation logic.

---

Nitpick comments:
In
`@Prezel/feature/history/impl/src/main/res/drawable/feature_history_impl_empty_no_presentation.xml`:
- Around line 7-20: Replace the repeated hard-coded color "#AFB3BA" in the
drawable by referencing a color resource: add a color named
feature_history_impl_empty_illustration to your colors.xml and update every
android:fillColor attribute in the drawable (all path elements using
android:fillColor="#AFB3BA") to use
`@color/feature_history_impl_empty_illustration` instead so the icon color is
centralized for theming and dark mode support.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3af2992a-3f83-4fcb-a70c-0cf51c6a4c7b

📥 Commits

Reviewing files that changed from the base of the PR and between 5cea85b and 563356a.

📒 Files selected for processing (19)
  • Prezel/core/model/src/main/java/com/team/prezel/core/model/presentation/Audience.kt
  • Prezel/core/model/src/main/java/com/team/prezel/core/model/presentation/Purpose.kt
  • Prezel/core/model/src/main/java/com/team/prezel/core/model/presentation/Style.kt
  • Prezel/feature/history/impl/build.gradle.kts
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryUiState.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryHeadSection.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryItemList.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiEffect.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiIntent.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiState.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/mapper/HistoryChipLabelMapper.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiMessage.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt
  • Prezel/feature/history/impl/src/main/res/drawable/feature_history_impl_empty_no_presentation.xml
  • Prezel/feature/history/impl/src/main/res/values/strings.xml
💤 Files with no reviewable changes (1)
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryUiState.kt

* feat: StatusView(EmptyView, ErrorView) 공통 컴포넌트 추가

`core:ui` 모듈에 빈 화면이나 에러 상태를 표시하기 위한 공통 UI 컴포넌트인 `StatusView`를 추가했습니다.

*   `EmptyView`, `ErrorView`: `StatusView`를 기반으로 한 상태별 컴포저블 추가
*   타이틀, 설명 문구, 이미지, 액션 버튼을 포함할 수 있는 유연한 구조 구현
*   디자인 시스템 테마(typography, colors, spacing) 적용 및 미리보기(Preview) 코드 추가
*   `core:ui` 모듈에 `core:designsystem` 의존성 추가

* refactor: History 피처 내 Empty 화면을 공통 컴포넌트로 대체

`feature:history:impl` 모듈의 `HistoryEmptyContent`를 신규 추가된 `EmptyView`를 사용하도록 리팩토링했습니다.

*   직접 구성하던 `Column` 레이아웃을 `EmptyView`로 교체하여 코드 중복 제거
*   탭 상태(`isPreparingTab`)에 따른 타이틀 및 액션 버튼 노출 로직 최적화
*   불필요한 내부 컴포넌트(`HistoryAddPresentationButton`) 및 import 제거
* feat: LoadingView 컴포넌트 및 로딩 애니메이션 추가

상태 화면을 표시하는 `StatusView`를 기반으로 로딩 상태를 위한 `LoadingView`를 추가하고, Lottie를 활용한 애니메이션 기능을 구현했습니다.

*   `LoadingView`: 제목, 설명과 함께 Lottie 애니메이션을 표시하는 공통 컴포넌트 추가
*   `LoadingLottie`: Lottie JSON 리소스를 받아 무한 반복 재생하는 내부 컴포넌트 구현
*   `asset_loading.json`: 로딩 화면에 사용될 Lottie 애니메이션 파일 추가
*   `LoadingViewPreview`: 디자인 시스템 확인을 위한 미리보기 코드 추가

* build: Lottie 의존성 추가

*   `libs.versions.toml`: `lottie-compose` 라이브러리(v6.6.7) 정의 추가
*   `core:ui`: `lottie-compose` 의존성 추가 및 관련 설정 업데이트
* refactor: `StatusView` 컴포넌트 통합 및 리팩터링

기존에 분리되어 있던 `EmptyView`, `ErrorView`, `LoadingView`를 단일 공통 컴포넌트인 `StatusView`로 통합하여 구조를 단순화했습니다.

*   `EmptyView`, `ErrorView`, `LoadingView` 삭제 및 `StatusView`로 단일화
*   `image` 파라미터 명칭을 `visual`로 변경하고 렌더링 로직 수정
*   `LoadingLottie`를 공통으로 사용 가능한 `StatusLottie`로 명칭 변경 및 가시성 수정(`private` -> `public`)
*   `HistoryEmptyContent` 등 호출부에서 변경된 `StatusView` 및 `visual` 파라미터 적용
*   상태별 프리뷰 코드(`StatusViewEmptyPreview`, `StatusViewErrorPreview`, `StatusViewLoadingPreview`) 최신화
* feat: HistoryPresentation 도메인 모델 추가 및 D-Day 계산 로직 구현

도메인 레이어에서 사용할 `HistoryPresentation` 모델을 추가하고, 현재 날짜 기반의 D-Day 계산 기능을 포함했습니다.

*   `HistoryPresentation` 데이터 클래스 추가 (`kotlinx-datetime` 활용)
*   `dDay()` 함수를 통해 대상 날짜와 현재 날짜 간의 차이 계산 로직 구현

* refactor: HistoryUiModel 구조 개선 및 UI 데이터 처리 로직 변경

UI 모델이 직접 날짜 데이터를 보유하고, 상태(준비 중/완료) 및 라벨(D-Day, 날짜 문자열)을 동적으로 계산하도록 리팩토링했습니다.

*   `HistoryUiModel`: 하드코딩된 `dDayLabel`, `dateLabel`을 제거하고 `LocalDate`를 직접 보유하도록 변경
*   `isPreparing`, `dDayLabel`, `dateLabel` 등 UI 표시를 위한 파생 프로퍼티 추가
*   `HistoryPresentationStatus` enum을 제거하고 `dDay` 값을 기준으로 상태를 판별하도록 변경
*   `HistoryPresentation`에서 `HistoryUiModel`로의 변환을 위한 `toUiModel` 매퍼 추가

* refactor: HistoryViewModel 및 화면 연동 로직 수정

Mock 데이터를 도메인 모델 기반으로 변경하고, 화면 전환 및 리스트 렌더링 로직을 개선했습니다.

*   `HistoryViewModel`: `HistoryPresentation` 리스트를 `toUiModel`을 통해 `HistoryUiState`로 변환하도록 수정
*   `HistoryScreen`: `HorizontalPager`의 페이지 전환 애니메이션을 제거하고, 불필요한 리스트 할당 로직을 `when` 조건문으로 최적화
*   `HistoryItemList`, `HistoryPresentationCard`: 변경된 `HistoryUiModel` 구조에 맞춰 프리뷰 및 내부 코드 수정
*   `history:impl` 모듈에 `kotlinx-datetime` 의존성 추가
*   **refactor: History 화면 내 탭 및 페이저 구조 개선**
    *   기존 `HistoryHeadSection` 컴포넌트를 제거하고 `HistoryScreen` 내부로 로직을 통합했습니다.
    *   `HorizontalPager`를 디자인 시스템 공통 컴포넌트인 `PrezelTabsPager`로 교체하여 일관성을 높였습니다.
    *   `PrezelTabsPager` 적용에 따라 별도의 `CoroutineScope`를 통한 `scrollToPage` 로직을 제거하고 선언적 탭 관리를 적용했습니다.
    *   각 탭의 콘텐츠(리스트 및 빈 화면) 배경색(`bgMedium`)과 탭 바 영역 배경색(`bgRegular`)을 명확히 구분하여 UI를 조정했습니다.

*   **style: History 관련 컴포넌트 위치 및 코드 정리**
    *   `historyTabs` 정의를 `HistoryScreen.kt` 내부로 이동했습니다.
    *   `HistoryPagerContent`에서 `Box`를 사용하여 각 페이지의 배경색과 레이아웃을 재설정했습니다.
    *   사용하지 않는 import와 파일을 정리했습니다.
Copy link
Copy Markdown
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

🧹 Nitpick comments (3)
Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt (1)

84-96: StatusLottie의 고정 크기 적용 방식을 개선하세요.

현재 코드에서 modifier.size(80.dp)가 함수 본문에서 강제 적용되어 있습니다. 기본 크기는 함수 시그니처의 기본값으로 제공하고, 함수 내부에서는 전달받은 modifier를 그대로 사용하는 것이 더 명확합니다.

♻️ 제안 수정안
 `@Composable`
 fun StatusLottie(
     `@RawRes` lottieJsonResId: Int,
-    modifier: Modifier = Modifier,
+    modifier: Modifier = Modifier.size(80.dp),
 ) {
@@
     LottieAnimation(
         composition = composition,
         progress = { progress },
-        modifier = modifier.size(80.dp),
+        modifier = modifier,
     )
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt` around
lines 84 - 96, The StatusLottie component currently forces a hardcoded size
inside the body; change the API to accept a size: Dp = 80.dp default parameter
on the StatusLottie function and replace the in-body call modifier.size(80.dp)
with modifier.size(size) so callers can override the size via the function
parameter while keeping 80.dp as the default; update any usages if needed and
keep the existing composition/animation logic (rememberLottieComposition,
animateLottieCompositionAsState, LottieAnimation) unchanged.
Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt (1)

111-112: 로딩 상태에서 빈 화면이 노출됩니다.

HistoryUiState.Loading일 때 아무것도 렌더링하지 않아 잠시 빈 화면이 보일 수 있습니다. 로딩 인디케이터를 추가하면 UX가 개선됩니다.

로딩 UI 추가 예시
     when (uiState) {
-        HistoryUiState.Loading -> Unit
+        HistoryUiState.Loading -> {
+            Box(
+                modifier = Modifier.fillMaxSize(),
+                contentAlignment = Alignment.Center,
+            ) {
+                CircularProgressIndicator()
+            }
+        }

         is HistoryUiState.Content -> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`
around lines 111 - 112, The when branch for HistoryUiState.Loading in
HistoryScreen currently returns Unit which shows a blank screen; replace that
branch to render a visible loading indicator (e.g., a centered
CircularProgressIndicator or your app's LoadingComposable) by wrapping it in a
Box/Column with Modifier.fillMaxSize() and contentAlignment = Alignment.Center
(or equivalent) so users see a spinner while uiState == HistoryUiState.Loading;
update the HistoryScreen's when(uiState) -> HistoryUiState.Loading branch to
call that loading UI instead of Unit.
Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt (1)

30-36: 실제 데이터 연동 시 에러 처리가 필요합니다.

현재 하드코딩된 데이터를 사용하므로 문제없지만, 실제 API 연동 시 try-catch와 HistoryUiEffect.ShowMessage 발송을 추가해야 합니다.

향후 구현 예시
private fun fetchData() {
    viewModelScope.launch {
        runCatching {
            // repository.fetchPresentations()
        }.onSuccess { presentations ->
            updateState { createHistoryContentState(presentations) }
        }.onFailure {
            sendEffect(HistoryUiEffect.ShowMessage(HistoryUiMessage.FETCH_DATA_FAILED))
        }
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt`
around lines 30 - 36, fetchData currently just calls updateState with
createHistoryContentState() and lacks error handling for real API calls; update
fetchData (the viewModelScope.launch block) to call the repository (e.g.,
repository.fetchPresentations()) inside a runCatching/try-catch, call
updateState { createHistoryContentState(presentations) } on success, and on
failure call
sendEffect(HistoryUiEffect.ShowMessage(HistoryUiMessage.FETCH_DATA_FAILED)) so
errors dispatch a UI message; ensure you reference the existing methods
fetchData, viewModelScope.launch, updateState, createHistoryContentState,
sendEffect, and HistoryUiEffect.ShowMessage in your changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Prezel/core/model/src/main/java/com/team/prezel/core/model/presentation/HistoryPresentation.kt`:
- Line 6: The file incorrectly imports kotlin.time.Clock while the code uses
Clock.System.todayIn(), which belongs to kotlinx.datetime.Clock; update the
import by removing kotlin.time.Clock and importing kotlinx.datetime.Clock (or
the appropriate kotlinx.datetime package) so Clock.System.todayIn() resolves to
the kotlinx.datetime implementation; ensure any other kotlinx.datetime types
used in HistoryPresentation (e.g., LocalDate) are imported consistently.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`:
- Around line 67-73: HistoryScreen의 onClickHistoryItem이 빈 람다로 되어 있어 클릭이 무반응합니다;
onClickHistoryItem 콜백을 구현하여 클릭된 HistoryItem의 상태(예: 준비중/완료)를 판별하고 상태에 따라 적절한
네비게이션을 트리거하도록 바꿔주세요. 구체적으로 HistoryScreen(...) 호출부에서 onClickHistoryItem = {
historyItem -> if (historyItem.isCompleted)
navController.navigate("analysis/${historyItem.id}") else
navController.navigate("preparation/${historyItem.id}") }처럼 HistoryItem을 인수로 받아
상태를 확인한 뒤 NavController 또는 제공된 네비게이터(예:
navigateToAnalysis/navigateToPreparation)를 호출하도록 연결해 주세요; 필요한 경우 HistoryItem의
식별자(id)와 상태 프로퍼티 이름을 사용해 맞춰 적용하세요.

---

Nitpick comments:
In `@Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt`:
- Around line 84-96: The StatusLottie component currently forces a hardcoded
size inside the body; change the API to accept a size: Dp = 80.dp default
parameter on the StatusLottie function and replace the in-body call
modifier.size(80.dp) with modifier.size(size) so callers can override the size
via the function parameter while keeping 80.dp as the default; update any usages
if needed and keep the existing composition/animation logic
(rememberLottieComposition, animateLottieCompositionAsState, LottieAnimation)
unchanged.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`:
- Around line 111-112: The when branch for HistoryUiState.Loading in
HistoryScreen currently returns Unit which shows a blank screen; replace that
branch to render a visible loading indicator (e.g., a centered
CircularProgressIndicator or your app's LoadingComposable) by wrapping it in a
Box/Column with Modifier.fillMaxSize() and contentAlignment = Alignment.Center
(or equivalent) so users see a spinner while uiState == HistoryUiState.Loading;
update the HistoryScreen's when(uiState) -> HistoryUiState.Loading branch to
call that loading UI instead of Unit.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt`:
- Around line 30-36: fetchData currently just calls updateState with
createHistoryContentState() and lacks error handling for real API calls; update
fetchData (the viewModelScope.launch block) to call the repository (e.g.,
repository.fetchPresentations()) inside a runCatching/try-catch, call
updateState { createHistoryContentState(presentations) } on success, and on
failure call
sendEffect(HistoryUiEffect.ShowMessage(HistoryUiMessage.FETCH_DATA_FAILED)) so
errors dispatch a UI message; ensure you reference the existing methods
fetchData, viewModelScope.launch, updateState, createHistoryContentState,
sendEffect, and HistoryUiEffect.ShowMessage in your changes.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7ed26be8-57f4-4f7f-a7c9-6eeb04a6f5e4

📥 Commits

Reviewing files that changed from the base of the PR and between 563356a and 29ca9b8.

📒 Files selected for processing (13)
  • Prezel/core/model/src/main/java/com/team/prezel/core/model/presentation/HistoryPresentation.kt
  • Prezel/core/ui/build.gradle.kts
  • Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt
  • Prezel/core/ui/src/main/res/raw/asset_loading.json
  • Prezel/feature/history/impl/build.gradle.kts
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryItemList.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/mapper/HistoryUiModelMapper.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt
  • Prezel/gradle/libs.versions.toml
✅ Files skipped from review due to trivial changes (3)
  • Prezel/core/ui/build.gradle.kts
  • Prezel/feature/history/impl/build.gradle.kts
  • Prezel/gradle/libs.versions.toml
🚧 Files skipped from review as they are similar to previous changes (3)
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryItemList.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt

…태 관리 로직을 리팩토링했습니다.

* **feat: 히스토리 페이지 UI 모델 추가**
    * 페이지 타입(`PREPARING`, `COMPLETED`)과 아이템 리스트를 포함하는 `HistoryPageUiModel` 데이터 클래스 추가
    * `HistoryUiState.Content`에서 각각 정의되어 있던 리스트를 `pages: ImmutableList<HistoryPageUiModel>` 형태로 통합

* **refactor: 히스토리 화면 및 탭 관리 로직 개선**
    * `HistoryScreen`에서 UI 상태(`pages`)를 기반으로 탭 목록을 동적으로 생성하도록 변경
    * `HistoryPagerContent`에서 페이지 인덱스 대신 `HistoryPageType`을 기준으로 빈 화면 여부 등을 판단하도록 수정
    * `HistoryViewModel`에서 도메인 모델을 `HistoryPageUiModel` 리스트로 변환하여 제공하도록 로직 업데이트
    * `HistoryScreen` 미리보기 코드에 변경된 상태 구조 반영

* **style: StatusLottie 컴포넌트 기본 크기 설정 방식 수정**
    * `StatusLottie`의 기본 크기(`80.dp`)를 `modifier` 파라미터의 기본값으로 이동하여 외부 커스텀이 용이하도록 개선
Copy link
Copy Markdown
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: 1

♻️ Duplicate comments (1)
Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt (1)

159-162: ⚠️ Potential issue | 🟠 Major

빈 상태 CTA가 아직 무반응입니다.

"발표 추가하기"가 준비 중 탭의 핵심 액션인데 현재 빈 람다라서 눌러도 아무 일도 일어나지 않습니다. 연동이 아직 없으면 버튼을 비활성화하고, 가능하면 상위에서 콜백을 주입해 실제 액션과 연결해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`
around lines 159 - 162, HistoryEmptyContent's onClickAddPresentation is a no-op,
so the "발표 추가하기" CTA does nothing; update HistoryScreen to either pass a real
callback from its parent into HistoryEmptyContent (forward an existing
addPresentation lambda) or change the call to disable the button when no handler
exists: detect whether a non-null callback is available (e.g.,
addPresentationCallback or similar injected into HistoryScreen) and pass it to
HistoryEmptyContent's onClickAddPresentation, and when page.type ==
HistoryPageType.PREPARING and no callback is provided, pass a disabled/no-op
state or an isEnabled=false flag so the button is visually and functionally
disabled instead of a silent no-op.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt`:
- Around line 58-95: The ViewModel currently embeds hardcoded sample entries in
the historyPresentations persistentList which makes FetchData always produce
dummy cards; remove the fixed data and instead initialize historyPresentations
as an empty persistent list (or derive it from an injected data source), modify
HistoryViewModel to accept a repository/dataSource (or a nullable list param)
and have fetchData/read state build Content from that injected source
(defaulting to empty list when no integration), and move the four sample
HistoryPresentation instances into preview/test-only code (e.g., a PreviewData
or test util) so production code shows real or empty history.

---

Duplicate comments:
In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`:
- Around line 159-162: HistoryEmptyContent's onClickAddPresentation is a no-op,
so the "발표 추가하기" CTA does nothing; update HistoryScreen to either pass a real
callback from its parent into HistoryEmptyContent (forward an existing
addPresentation lambda) or change the call to disable the button when no handler
exists: detect whether a non-null callback is available (e.g.,
addPresentationCallback or similar injected into HistoryScreen) and pass it to
HistoryEmptyContent's onClickAddPresentation, and when page.type ==
HistoryPageType.PREPARING and no callback is provided, pass a disabled/no-op
state or an isEnabled=false flag so the button is visually and functionally
disabled instead of a silent no-op.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5f3d2d7e-f32b-4e44-964a-b16f85d8fa5a

📥 Commits

Reviewing files that changed from the base of the PR and between 29ca9b8 and 671ac85.

📒 Files selected for processing (5)
  • Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/contract/HistoryUiState.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryPageUiModel.kt
✅ Files skipped from review due to trivial changes (1)
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryPageUiModel.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • Prezel/core/ui/src/main/java/com/team/prezel/core/ui/StatusView.kt

@HamBeomJoon HamBeomJoon requested a review from moondev03 April 16, 2026 10:58
* refactor: `HistoryUiModel` 내 매퍼 로직 통합 및 속성 개선

- 외부 매퍼 파일(`HistoryUiModelMapper.kt`)을 제거하고 `HistoryUiModel.companion.toUiModel`로 통합했습니다.
- `isPreparing`, `dDayLabel`, `dateLabel` 프로퍼티의 getter를 필드 초기화 방식으로 변경하여 효율성을 높였습니다.

* refactor: `HistoryScreen` 탭 관리 및 렌더링 로직 개선

- 탭 리스트(`tabs`)를 UI 상태와 독립적으로 정의하고 `remember`를 사용하여 불필요한 재계산을 방지했습니다.
- `HistoryPagerContent`를 별도 컴포저블로 분리하지 않고 `HistoryScreen` 내에서 직접 처리하도록 구조를 단순화했습니다.
- 페이지 타입(`HISTORY_PAGE_TYPES`)을 상수로 정의하여 인덱스 기반의 페이지 매핑 로직을 개선했습니다.
- 로딩 상태를 명시적으로 처리하기 위해 `CircularProgressIndicator`를 추가했습니다.

* refactor: `HistoryEmptyContent` 및 카드 컴포넌트 개선

- `isPreparingTab` Boolean 파라미터를 `HistoryPageType` enum으로 대체하여 명확성을 높였습니다.
- `HistoryChipLabelMapper.kt`를 제거하고, 관련 리소스 ID 매핑 함수(`labelResId`)를 `HistoryPresentationCard.kt` 내부의 private 함수로 이동하여 캡슐화했습니다.

* chore: 불필요한 매퍼 파일 및 미사용 import 제거

- `HistoryChipLabelMapper.kt`, `HistoryUiModelMapper.kt` 파일을 삭제했습니다.
- `HistoryViewModel`에서 제거된 매퍼 대신 `HistoryUiModel.toUiModel`을 사용하도록 수정했습니다.
Copy link
Copy Markdown
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.

🧹 Nitpick comments (2)
Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt (1)

54-67: LaunchedEffect 내 일회성 호출과 지속적 수집 혼용

FetchData 인텐트 디스패치(일회성)와 uiEffect 수집(지속적)이 같은 LaunchedEffect 블록에 있습니다. FetchDataUnit 키로 한 번만 실행되어야 하고, uiEffect는 지속적으로 수집되어야 하므로 의도는 맞지만, 분리하면 의도가 더 명확해집니다.

♻️ 분리 제안
     LaunchedEffect(Unit) {
         viewModel.onIntent(HistoryUiIntent.FetchData)
+    }
 
+    LaunchedEffect(Unit) {
         viewModel.uiEffect.collect { effect ->
             when (effect) {
                 is HistoryUiEffect.ShowMessage -> {
                     val resId = when (effect.message) {
                         HistoryUiMessage.FETCH_DATA_FAILED -> R.string.feature_history_impl_fetch_data_failed
                     }
                     snackbarHostState.showPrezelSnackbar(message = resources.getString(resId))
                 }
             }
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`
around lines 54 - 67, 현재 LaunchedEffect(Unit) 블록에서 일회성 호출
viewModel.onIntent(HistoryUiIntent.FetchData)와 지속적 수집
viewModel.uiEffect.collect(...)를 섞어 사용하고 있어 의도가 모호하므로, 이를 분리하세요: 하나의
LaunchedEffect(Unit) 또는 DisposableEffect에서
viewModel.onIntent(HistoryUiIntent.FetchData)를 한 번만 호출하도록 두고, 별도의
LaunchedEffect(key1 = viewModel) 또는 rememberCoroutineScope/LaunchedEffect(true)
블록에서 viewModel.uiEffect.collect { ... }를 지속적으로 수집하도록 옮겨
snackbarHostState.showPrezelSnackbar 호출을 유지해 주세요.
Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt (1)

33-47: toUiModel 네이밍 컨벤션 검토

toUiModel 메서드는 일반적으로 변환되는 객체에서 호출되는 확장 함수 패턴(HistoryPresentation.toUiModel())에 사용됩니다. companion object의 팩토리 메서드는 from()이나 create() 같은 이름이 더 직관적입니다.

현재 사용법(HistoryUiModel::toUiModel)은 동작하지만, 코드 가독성을 위해 고려해 볼 수 있습니다.

♻️ 대안: 확장 함수로 변환
-    companion object {
-        fun toUiModel(historyPresentation: HistoryPresentation): HistoryUiModel {
-            val dDay = historyPresentation.dDay()
-            return HistoryUiModel(
-                id = historyPresentation.id,
-                dDay = dDay,
-                date = historyPresentation.date,
-                title = historyPresentation.title,
-                category = historyPresentation.category,
-                purpose = historyPresentation.purpose,
-                style = historyPresentation.style,
-                audience = historyPresentation.audience,
-            )
-        }
-    }
+}
+
+internal fun HistoryPresentation.toUiModel(): HistoryUiModel {
+    val dDay = dDay()
+    return HistoryUiModel(
+        id = id,
+        dDay = dDay,
+        date = date,
+        title = title,
+        category = category,
+        purpose = purpose,
+        style = style,
+        audience = audience,
+    )
 }

ViewModel 사용부도 함께 수정:

-            .map(HistoryUiModel::toUiModel)
+            .map(HistoryPresentation::toUiModel)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt`
around lines 33 - 47, The companion object's factory method named toUiModel
should be renamed to a clearer factory-style name (e.g., from or create) or
converted into an extension function on HistoryPresentation; update the
companion object method in HistoryUiModel (currently fun
toUiModel(historyPresentation: HistoryPresentation): HistoryUiModel) to the
chosen name (e.g., fun from(historyPresentation: HistoryPresentation):
HistoryUiModel) and then update all call sites that reference
HistoryUiModel::toUiModel or call HistoryUiModel.toUiModel(...) to use the new
factory name (or, if converting to an extension, implement
HistoryPresentation.toUiModel() and replace usages accordingly) while preserving
the existing construction logic and fields (id, dDay, date, title, category,
purpose, style, audience).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt`:
- Around line 54-67: 현재 LaunchedEffect(Unit) 블록에서 일회성 호출
viewModel.onIntent(HistoryUiIntent.FetchData)와 지속적 수집
viewModel.uiEffect.collect(...)를 섞어 사용하고 있어 의도가 모호하므로, 이를 분리하세요: 하나의
LaunchedEffect(Unit) 또는 DisposableEffect에서
viewModel.onIntent(HistoryUiIntent.FetchData)를 한 번만 호출하도록 두고, 별도의
LaunchedEffect(key1 = viewModel) 또는 rememberCoroutineScope/LaunchedEffect(true)
블록에서 viewModel.uiEffect.collect { ... }를 지속적으로 수집하도록 옮겨
snackbarHostState.showPrezelSnackbar 호출을 유지해 주세요.

In
`@Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt`:
- Around line 33-47: The companion object's factory method named toUiModel
should be renamed to a clearer factory-style name (e.g., from or create) or
converted into an extension function on HistoryPresentation; update the
companion object method in HistoryUiModel (currently fun
toUiModel(historyPresentation: HistoryPresentation): HistoryUiModel) to the
chosen name (e.g., fun from(historyPresentation: HistoryPresentation):
HistoryUiModel) and then update all call sites that reference
HistoryUiModel::toUiModel or call HistoryUiModel.toUiModel(...) to use the new
factory name (or, if converting to an extension, implement
HistoryPresentation.toUiModel() and replace usages accordingly) while preserving
the existing construction logic and fields (id, dDay, date, title, category,
purpose, style, audience).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e1555b1c-064d-4c24-8f2c-81e547a8be37

📥 Commits

Reviewing files that changed from the base of the PR and between 671ac85 and 42ebb5e.

📒 Files selected for processing (5)
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryScreen.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/HistoryViewModel.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryEmptyContent.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt
  • Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/model/HistoryUiModel.kt

* refactor: `HistoryPresentation` 모델 제거 및 `Presentation`으로 통합

기존에 분리되어 있던 `HistoryPresentation` 클래스를 삭제하고 `Presentation` 클래스를 사용하도록 통합했습니다.
* `HistoryUiModel.toUiModel` 파라미터 타입을 `HistoryPresentation`에서 `Presentation`으로 변경
* `HistoryViewModel`의 더미 데이터 타입을 `Presentation`으로 변경

* feat: `Presentation` 데이터 모델 필드 추가 및 순서 조정

`Presentation` 클래스에 발표 상세 정보를 나타내는 필드를 추가하고 구조를 개선했습니다.
* `purpose`, `style`, `audience` 필드 추가
* 필드 선언 순서 변경 (`id`, `title`, `date`, `category`, ...)
* `HomeViewModel` 내 더미 데이터 생성 시 신규 필드 값 추가

* chore: `HistoryScreen` 내 `LaunchedEffect` 로직 분리

데이터 페칭(`FetchData`) 로직과 UI 효과(`uiEffect`) 수집 로직을 별도의 `LaunchedEffect` 블록으로 분리하여 관리하도록 수정했습니다.
@HamBeomJoon HamBeomJoon merged commit 0313175 into develop Apr 16, 2026
2 checks passed
@HamBeomJoon HamBeomJoon deleted the feat/#98-history-view branch April 16, 2026 16:44
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.

히스토리 화면 view 구현

2 participants