Skip to content

[Feat] 감정 구슬 상세 화면 UI 구현#92

Merged
choijungp merged 3 commits into
developfrom
feat/emotionDetailView
Jul 14, 2026
Merged

[Feat] 감정 구슬 상세 화면 UI 구현#92
choijungp merged 3 commits into
developfrom
feat/emotionDetailView

Conversation

@choijungp

@choijungp choijungp commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🌁 Background

감정 구슬 기록 달력에서 감정을 누를 때 보이는 감정 구슬 상세 화면 UI를 구현했어요 ~

📱 Screenshot

iPhone SE3 iPhone 13 mini iPhone 16 Pro
Simulator Screenshot - iPhone SE (3rd generation) - 2026-07-13 at 18 43 54 Simulator Screenshot - iPhone 13 mini - 2026-07-13 at 18 43 05 Simulator Screenshot - iPhone 16 Pro - 2026-07-13 at 18 42 05

👩‍💻 Contents

  • 감정 구슬 상세 화면 EmotionDetailViewController 구현

Summary by CodeRabbit

  • 새로운 기능

    • 감정 기록 상세 화면에 감정별 설명, 그래픽 이미지, 날짜 정보가 표시됩니다.
    • 불안, 차분함, 피로, 무기력, 만족, 활력 감정 그래픽을 지원합니다.
    • 감정 상세 화면에 닫기 버튼과 부드러운 배경 전환 효과가 추가되었습니다.
    • 날짜를 “YYYY년 M월 D일” 형식으로 표시할 수 있습니다.
  • 개선 사항

    • 기록이 있는 날짜만 감정 캘린더에서 선택할 수 있습니다.
    • 감정 상세 화면의 크기, 모서리, 스크롤 동작이 개선되었습니다.

@choijungp
choijungp requested a review from taipaise July 13, 2026 09:44
@choijungp choijungp self-assigned this Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

감정별 그래픽과 설명 데이터가 추가되고, 감정 상세 화면이 날짜·설명·이미지를 표시하도록 확장되었습니다. 활동 기록 화면에는 디밍 오버레이와 조정된 시트 표시 설정이 적용되며, 감정 기록이 있는 날짜만 선택할 수 있습니다.

Changes

감정 상세 화면 흐름

Layer / File(s) Summary
감정 데이터와 그래픽 리소스
Projects/Presentation/Resources/Images.xcassets/EmotionActivity/..., Projects/Presentation/Sources/Common/DesignSystem/BitnagilGraphic.swift, Projects/Presentation/Sources/EmotionRegister/Model/Emotion.swift, Projects/Shared/Sources/Extension/Date+.swift
감정별 1x·2x·3x 이미지셋, 설명 문자열, 그래픽 매핑과 yyyy년 M월 d일 날짜 포맷이 추가되었습니다.
감정 상세 UI
Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift
상세 화면이 날짜, 감정 설명, 감정 그래픽, 닫기 버튼을 구성하며 화면 종료 시 onDismiss를 호출합니다.
활동 기록 표시 흐름
Projects/Presentation/Sources/ActivityHistory/View/ActivityHistoryViewController.swift, Projects/Presentation/Sources/ActivityHistory/View/Component/EmotionCalendarView.swift
감정 상세 시트와 디밍 오버레이 동작이 조정되고, 감정 기록이 있는 날짜만 캘린더에서 선택됩니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: taipaise

Poem

토끼가 새 그래픽을 당근처럼 심고
감정의 결을 화면에 곱게 피웠네
달력은 기록 있는 날만 살짝 열고
상세 시트는 포근히 내려오네
닫히면 그림자도 사라져 깡총! 🐰

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 감정 구슬 상세 화면 UI 구현과 관련된 변경 사항(상세 화면, 이미지 에셋, 달력 선택 제어)을 잘 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 feat/emotionDetailView

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.

@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

🧹 Nitpick comments (3)
Projects/Presentation/Sources/ActivityHistory/View/ActivityHistoryViewController.swift (1)

196-206: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

dimmedView가 고정 frame이라 회전/크기 변경 시 전체 화면을 덮지 못할 수 있습니다.

newDimmedView.frame = view.bounds로 한 번만 프레임을 지정하고 autoresizingMask나 오토레이아웃 제약이 없습니다. 디바이스 회전이나 사이즈 클래스 변경이 발생하면 오버레이가 새로운 bounds로 갱신되지 않아 화면 일부만 덮는 시각적 결함이 생길 수 있습니다. 코드베이스 전반에서 SnapKit을 사용하는 관례와도 일치하지 않습니다.

♻️ 제안하는 수정
         let newDimmedView = UIView()
         newDimmedView.backgroundColor = .black.withAlphaComponent(0.0)
-        newDimmedView.frame = view.bounds
         view.addSubview(newDimmedView)
+        newDimmedView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
         dimmedView = newDimmedView
🤖 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
`@Projects/Presentation/Sources/ActivityHistory/View/ActivityHistoryViewController.swift`
around lines 196 - 206, Update the dimmedView setup in the surrounding overlay
presentation method so newDimmedView remains pinned to view’s edges after
rotation and size changes. Replace the one-time frame assignment with the
project’s established SnapKit constraints (or equivalent edge constraints), and
ensure the view is configured for Auto Layout before constraining it; preserve
the existing dimming animation.
Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift (1)

50-53: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

viewDidDisappear 기반 onDismiss 호출은 "가려짐"과 "실제 dismiss"를 구분하지 못합니다.

viewDidDisappear는 실제 dismiss뿐 아니라 이 화면 위에 다른 화면(예: alert)이 추가로 present되어 가려지는 경우에도 호출됩니다. 현재 흐름에서는 문제가 없지만, 추후 이 화면에서 다른 화면을 present하게 되면 ActivityHistoryViewControllerdimmedView가 시트가 아직 떠 있는 상태에서 사라지는 버그가 발생할 수 있습니다.

UIAdaptivePresentationControllerDelegate.presentationControllerDidDismiss(_:)를 사용하면 실제 dismiss(스와이프 포함)에만 반응하여 더 안전합니다.

🤖 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
`@Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift`
around lines 50 - 53, Replace the onDismiss call in
ActivityHistoryViewController.viewDidDisappear with
UIAdaptivePresentationControllerDelegate.presentationControllerDidDismiss(_:) so
callbacks occur only after the presentation is actually dismissed, including
interactive swipe dismissals. Make ActivityHistoryViewController conform to the
delegate and invoke onDismiss from presentationControllerDidDismiss instead of
viewDidDisappear.
Projects/Presentation/Sources/EmotionRegister/Model/Emotion.swift (1)

204-239: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

emotionDescription와 기존 description 간 텍스트 중복

emotionDescriptiondescription의 핵심 문구 앞에 "이날은 ___했나봐요! " 접두사를 붙인 형태입니다. 두 프로퍼티가 동일한 설명 텍스트를 각각 하드코딩하고 있어, 문구 수정 시 양쪽을 모두 업데이트해야 하는 유지보수 리스크가 있습니다.

또한 CALM(Line 210), LETHARGY(Line 220), ANXIETY(Line 225) 케이스의 첫 번째 줄 끝에 후행 공백이 포함되어 있으며, VITALITY·SATISFACTION·FATIGUE에는 없어 일관성이 깨집니다. Swift 멀티라인 문자열 리터럴에서 후행 공백은 문자열에 포함되어 렌더링 시 미세한 레이아웃 차이를 유발할 수 있습니다.

♻️ 후행 공백 제거 제안
         case .CALM:
             """
-            이날은 평온했나봐요! 평온함은 마음이 고요하고 
+            이날은 평온했나봐요! 평온함은 마음이 고요하고
             편안해 균형을 이루는 상태예요.
             """
         case .VITALITY:
             """
             이날은 활기찼나봐요! 활기참은 생기가 가득 차
             활발하고 적극적인 상태예요.
             """
         case .LETHARGY:
             """
-            이날은 무기력했나봐요! 무기력함은 의욕이 없어 
+            이날은 무기력했나봐요! 무기력함은 의욕이 없어
             아무것도 하기 힘든 상태예요.
             """
         case .ANXIETY:
             """
-            이날은 불안했나봐요! 불안함은 마음이 불안정하고 
+            이날은 불안했나봐요! 불안함은 마음이 불안정하고
             쉽게 안심하기 어려운 상태예요.
             """
🤖 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 `@Projects/Presentation/Sources/EmotionRegister/Model/Emotion.swift` around
lines 204 - 239, Update emotionDescription to compose each emotion’s prefix with
the existing description property instead of duplicating the description text,
preserving the current output. Remove trailing spaces from the CALM, LETHARGY,
and ANXIETY multiline string lines, and keep formatting consistent across all
cases.
🤖 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
`@Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift`:
- Around line 106-109: Update the descriptionLabel constraints in
EmotionDetailViewController so its available width is bounded by adding a
trailing constraint or equivalent width constraint alongside the existing
leading constraint. Preserve the two-line numberOfLines configuration and ensure
the label wraps within the screen margins.

---

Nitpick comments:
In
`@Projects/Presentation/Sources/ActivityHistory/View/ActivityHistoryViewController.swift`:
- Around line 196-206: Update the dimmedView setup in the surrounding overlay
presentation method so newDimmedView remains pinned to view’s edges after
rotation and size changes. Replace the one-time frame assignment with the
project’s established SnapKit constraints (or equivalent edge constraints), and
ensure the view is configured for Auto Layout before constraining it; preserve
the existing dimming animation.

In
`@Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift`:
- Around line 50-53: Replace the onDismiss call in
ActivityHistoryViewController.viewDidDisappear with
UIAdaptivePresentationControllerDelegate.presentationControllerDidDismiss(_:) so
callbacks occur only after the presentation is actually dismissed, including
interactive swipe dismissals. Make ActivityHistoryViewController conform to the
delegate and invoke onDismiss from presentationControllerDidDismiss instead of
viewDidDisappear.

In `@Projects/Presentation/Sources/EmotionRegister/Model/Emotion.swift`:
- Around line 204-239: Update emotionDescription to compose each emotion’s
prefix with the existing description property instead of duplicating the
description text, preserving the current output. Remove trailing spaces from the
CALM, LETHARGY, and ANXIETY multiline string lines, and keep formatting
consistent across all cases.
🪄 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: 10b3a6c2-cb51-457a-b3d4-179ec476a06a

📥 Commits

Reviewing files that changed from the base of the PR and between a073e4a and 9b0c84c.

⛔ Files ignored due to path filters (18)
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/anxiety_emotion_graphic.imageset/anxiety_emotion_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/anxiety_emotion_graphic.imageset/anxiety_emotion_graphic@2x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/anxiety_emotion_graphic.imageset/anxiety_emotion_graphic@3x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/calm_emotion_graphic.imageset/calm_emotion_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/calm_emotion_graphic.imageset/calm_emotion_graphic@2x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/calm_emotion_graphic.imageset/calm_emotion_graphic@3x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/fatigue_emotion_graphic.imageset/fatigue_emotion_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/fatigue_emotion_graphic.imageset/fatigue_emotion_graphic@2x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/fatigue_emotion_graphic.imageset/fatigue_emotion_graphic@3x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/lethargy_emotion_graphic.imageset/lethargy_emotion_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/lethargy_emotion_graphic.imageset/lethargy_emotion_graphic@2x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/lethargy_emotion_graphic.imageset/lethargy_emotion_graphic@3x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/satisfaction_emotion_graphic.imageset/satisfaction_emotion_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/satisfaction_emotion_graphic.imageset/satisfaction_emotion_graphic@2x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/satisfaction_emotion_graphic.imageset/satisfaction_emotion_graphic@3x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/vitality_emotion_graphic.imageset/vitality_emotion_graphic.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/vitality_emotion_graphic.imageset/vitality_emotion_graphic@2x.png is excluded by !**/*.png
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/vitality_emotion_graphic.imageset/vitality_emotion_graphic@3x.png is excluded by !**/*.png
📒 Files selected for processing (13)
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/Contents.json
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/anxiety_emotion_graphic.imageset/Contents.json
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/calm_emotion_graphic.imageset/Contents.json
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/fatigue_emotion_graphic.imageset/Contents.json
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/lethargy_emotion_graphic.imageset/Contents.json
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/satisfaction_emotion_graphic.imageset/Contents.json
  • Projects/Presentation/Resources/Images.xcassets/EmotionActivity/vitality_emotion_graphic.imageset/Contents.json
  • Projects/Presentation/Sources/ActivityHistory/View/ActivityHistoryViewController.swift
  • Projects/Presentation/Sources/ActivityHistory/View/Component/EmotionCalendarView.swift
  • Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift
  • Projects/Presentation/Sources/Common/DesignSystem/BitnagilGraphic.swift
  • Projects/Presentation/Sources/EmotionRegister/Model/Emotion.swift
  • Projects/Shared/Sources/Extension/Date+.swift

Comment on lines +106 to +109
descriptionLabel.snp.makeConstraints { make in
make.top.equalTo(headerStackView.snp.bottom)
make.leading.equalToSuperview().offset(Layout.horizontalMargin)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

descriptionLabel에 trailing/width 제약이 없어 2줄 줄바꿈이 깨질 수 있습니다.

numberOfLines = 2만 설정하고 leading만 고정되어 있어, 라벨의 preferredMaxLayoutWidth를 결정할 폭 제약이 없습니다. 이 경우 UILabel의 intrinsicContentSize는 줄바꿈 없는 한 줄 기준으로 계산되어 텍스트가 화면 우측으로 넘치거나 잘릴 수 있습니다(목업의 "이날은 평온했나봐요! 평온함은..." 2줄 표시와 다르게 렌더링될 위험).

🐛 제안하는 수정
         descriptionLabel.snp.makeConstraints { make in
             make.top.equalTo(headerStackView.snp.bottom)
             make.leading.equalToSuperview().offset(Layout.horizontalMargin)
+            make.trailing.equalToSuperview().inset(Layout.horizontalMargin)
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
descriptionLabel.snp.makeConstraints { make in
make.top.equalTo(headerStackView.snp.bottom)
make.leading.equalToSuperview().offset(Layout.horizontalMargin)
}
descriptionLabel.snp.makeConstraints { make in
make.top.equalTo(headerStackView.snp.bottom)
make.leading.equalToSuperview().offset(Layout.horizontalMargin)
make.trailing.equalToSuperview().inset(Layout.horizontalMargin)
}
🤖 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
`@Projects/Presentation/Sources/ActivityHistory/View/EmotionDetailViewController.swift`
around lines 106 - 109, Update the descriptionLabel constraints in
EmotionDetailViewController so its available width is bounded by adding a
trailing constraint or equivalent width constraint alongside the existing
leading constraint. Preserve the two-line numberOfLines configuration and ensure
the label wraps within the screen margins.

@taipaise taipaise left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

오늘도 고생하셨습니다@!@!@!@!

@choijungp
choijungp merged commit 0b9598d into develop Jul 14, 2026
2 checks passed
@choijungp
choijungp deleted the feat/emotionDetailView branch July 14, 2026 07:34
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.

2 participants