From 25c7ecd7e859cc0b4757066defbf2726d474f51f Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:36:44 +0900 Subject: [PATCH 01/21] =?UTF-8?q?[BOOK-499]=20feat:=20=E2=80=9C=EB=82=B4?= =?UTF-8?q?=20=EA=B8=B0=EB=A1=9D=20=EB=AA=A8=EC=9D=8C=E2=80=9D=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/MainFlow/BookDetail/View/BookDetailViewHeader.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewHeader.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewHeader.swift index 050ed24b..c48549a9 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewHeader.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewHeader.swift @@ -9,7 +9,7 @@ final class BookDetailViewHeader: BaseView { private let titleLabel = BKLabel( fontStyle: .headline2(weight: .semiBold), - highlightColor: .bkContentColor(.brand) + highlightColor: .bkContentColor(.tertiary) ) private let sortButtonStack: UIStackView = { From f198b074681a5ffb88088740feee6a18bab0ffe9 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:37:10 +0900 Subject: [PATCH 02/21] =?UTF-8?q?[BOOK-499]=20feat:=20=EB=8F=84=EC=84=9C?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=ED=97=A4=EB=8D=94=20=EA=B0=84=EA=B2=A9?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainFlow/BookDetail/View/BookDetailView.swift | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift index f433379a..2ea76cc8 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift @@ -38,6 +38,15 @@ final class BookDetailView: BaseView { stackView.spacing = LayoutConstants.buttonGroupSpacing stackView.distribution = .fill stackView.alignment = .fill + + stackView.isLayoutMarginsRelativeArrangement = true + stackView.layoutMargins = UIEdgeInsets( + top: LayoutConstants.buttonGroupHSpacing, + left: 0, + bottom: LayoutConstants.buttonGroupHSpacing, + right: 0 + ) + return stackView }() @@ -142,7 +151,6 @@ final class BookDetailView: BaseView { seedReportView.snp.makeConstraints { $0.top.equalTo(buttonGroup.snp.bottom) - .offset(LayoutConstants.seedReportViewTopInset) $0.horizontalEdges.equalToSuperview() .inset(LayoutConstants.horizontalInset) seedReportZeroHeight = $0.height.equalTo(0).priority(.low).constraint @@ -366,8 +374,8 @@ private extension BookDetailView { static let summaryViewTopInset = BKInset.inset2 static let summaryViewHeight: CGFloat = 98 static let buttonGroupSpacing = BKSpacing.spacing2 - static let buttonGroupTopInset = BKInset.inset8 - static let seedReportViewTopInset = BKInset.inset8 + static let buttonGroupHSpacing = BKSpacing.spacing4 + static let buttonGroupTopInset = BKSpacing.spacing1 static let dividerVerticalOffset = BKInset.inset6 static let collectionViewTopOffset = BKInset.inset4 static let collectionViewCellMaxHeight: CGFloat = 180 From c348d2e3bb37968da4f1aa9ce4b22d54585508dc Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:38:48 +0900 Subject: [PATCH 03/21] =?UTF-8?q?[BOOK-499]=20feat:=20=E2=80=9C=EB=82=B4?= =?UTF-8?q?=20=EA=B8=B0=EB=A1=9D=20=EB=AA=A8=EC=9D=8C=E2=80=9D=20=EC=83=81?= =?UTF-8?q?=EB=8B=A8=20=EA=B0=84=EA=B2=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/MainFlow/BookDetail/View/BookDetailView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift index 2ea76cc8..3af08459 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift @@ -376,7 +376,7 @@ private extension BookDetailView { static let buttonGroupSpacing = BKSpacing.spacing2 static let buttonGroupHSpacing = BKSpacing.spacing4 static let buttonGroupTopInset = BKSpacing.spacing1 - static let dividerVerticalOffset = BKInset.inset6 + static let dividerVerticalOffset = BKInset.inset8 static let collectionViewTopOffset = BKInset.inset4 static let collectionViewCellMaxHeight: CGFloat = 180 static let collectionViewCellSpacing = BKSpacing.spacing3 From 10091097eb785cdea3299f69cfe07584a54ad657 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sun, 8 Feb 2026 21:03:39 +0900 Subject: [PATCH 04/21] =?UTF-8?q?[BOOK-499]=20feat:=20BookDetailItem=20pag?= =?UTF-8?q?e=20->=20Int=3F=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Projects/BKCore/Sources/Extension/Optional.swift | 10 ++++++++++ .../MainFlow/BookDetail/Models/BookDetailItem.swift | 2 +- .../MainFlow/BookDetail/View/BookDetailView.swift | 11 ++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/Projects/BKCore/Sources/Extension/Optional.swift diff --git a/src/Projects/BKCore/Sources/Extension/Optional.swift b/src/Projects/BKCore/Sources/Extension/Optional.swift new file mode 100644 index 00000000..556d2798 --- /dev/null +++ b/src/Projects/BKCore/Sources/Extension/Optional.swift @@ -0,0 +1,10 @@ +// Copyright © 2026 Booket. All rights reserved + +import UIKit + +public extension Optional where Wrapped == Int { + /// Int? 값을 "123p" 또는 값이 없을 경우 "-p" 문자열로 반환합니다. + var toPageString: String { + return self.map { "\($0)p" } ?? "-p" + } +} diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/BookDetailItem.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/BookDetailItem.swift index 9a176921..6bd4f321 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/BookDetailItem.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/BookDetailItem.swift @@ -14,7 +14,7 @@ struct BookDetailItem: Hashable { /// 감정 let emotion: EmotionSeed? let createdAt: Date - let page: Int + let page: Int? let bookTitle: String static func from(recordInfo: RecordInfo) -> Self { diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift index 3af08459..08566cba 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift @@ -19,7 +19,16 @@ enum SortOption: String, CaseIterable { case .newest: return { $0.createdAt > $1.createdAt } case .pageDescending: - return { $0.page > $1.page } + return { + let p0 = $0.page ?? Int.max + let p1 = $1.page ?? Int.max + + if p0 == p1 { + return $0.createdAt > $1.createdAt + } + + return p0 > p1 + } } } } From e89a389c2ecac607823818d3ab74e603ab292946 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sun, 8 Feb 2026 21:41:11 +0900 Subject: [PATCH 05/21] =?UTF-8?q?[BOOK-499]=20feat:=20BookDetailViewCell?= =?UTF-8?q?=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookDetail/View/BookDetailViewCell.swift | 48 ++++++------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewCell.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewCell.swift index 74dcb76e..a51c9ee8 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewCell.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewCell.swift @@ -1,6 +1,7 @@ // Copyright © 2025 Booket. All rights reserved import BKDesign +import BKCore import SnapKit import UIKit @@ -20,9 +21,8 @@ final class BookDetailViewCell: UICollectionViewCell { return stackView }() - private let emotionIcon = UIImageView() - private let emotionLabel = BKLabel2( - fontStyle: .body1(weight: .semiBold), + private let pageLabel = BKLabel2( + fontStyle: .italic, color: .bkContentColor(.brand) ) @@ -31,8 +31,8 @@ final class BookDetailViewCell: UICollectionViewCell { color: .bkContentColor(.tertiary) ) - private let pageLabel = BKLabel2( - fontStyle: .italic, + private let emotionTagLabel = BKLabel2( + fontStyle: .label1(weight: .medium), color: .bkContentColor(.tertiary) ) @@ -56,14 +56,6 @@ final class BookDetailViewCell: UICollectionViewCell { return stackView }() - private let emotionStack: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = LayoutConstants.emotionStackSpacing - stackView.alignment = .center - return stackView - }() - override init(frame: CGRect) { super.init(frame: frame) setupViews() @@ -78,10 +70,9 @@ final class BookDetailViewCell: UICollectionViewCell { override func prepareForReuse() { super.prepareForReuse() noteLabel.setText(text: "") - emotionIcon.image = nil - emotionLabel.setText(text: "") - creationLabel.setText(text: "") pageLabel.setText(text: "") + creationLabel.setText(text: "") + emotionTagLabel.setText(text: "") } func configure( @@ -91,11 +82,9 @@ final class BookDetailViewCell: UICollectionViewCell { let displayedNote = "\"\(item.note)\"" noteLabel.setText(text: displayedNote) - emotionIcon.image = emotion.circleImage - emotionIcon.contentMode = .scaleAspectFit - emotionLabel.setText(text: "#\(emotion.rawValue)") + pageLabel.setText(text: item.page.toPageString) creationLabel.setText(text: item.createdAt.toKoreanDotDateString()) - pageLabel.setText(text: "\(item.page)p") + emotionTagLabel.setText(text: "#\(emotion.rawValue)") } func applyMoreButtonGesture( @@ -113,9 +102,8 @@ final class BookDetailViewCell: UICollectionViewCell { private extension BookDetailViewCell { func setupViews() { contentView.addSubviews(upperStack, noteLabel, lowerStack) - [emotionStack, moreButton].forEach(upperStack.addArrangedSubview) - [creationLabel, pageLabel].forEach(lowerStack.addArrangedSubview) - [emotionIcon, emotionLabel].forEach(emotionStack.addArrangedSubview) + [pageLabel, moreButton].forEach(upperStack.addArrangedSubview) + [emotionTagLabel, creationLabel].forEach(lowerStack.addArrangedSubview) } func configure() { @@ -151,6 +139,7 @@ private extension BookDetailViewCell { .offset(LayoutConstants.lowerLabelTopInset) $0.horizontalEdges.equalToSuperview() .inset(LayoutConstants.horizontalInset) + $0.height.equalTo(LayoutConstants.lowerLabelHeight) $0.bottom.equalToSuperview() .inset(LayoutConstants.bottomInset) } @@ -158,10 +147,6 @@ private extension BookDetailViewCell { moreButton.snp.makeConstraints { $0.size.equalTo(LayoutConstants.moreButtonSize) } - - emotionIcon.snp.makeConstraints { - $0.size.equalTo(LayoutConstants.emotionImageSize) - } } @objc func handleMoreButtonTapped() { @@ -171,17 +156,14 @@ private extension BookDetailViewCell { private extension BookDetailViewCell { enum LayoutConstants { - static let emotionStackSpacing = BKSpacing.spacing2 - static let noteLabelTopInset = BKInset.inset3 - static let lowerLabelTopInset = BKInset.inset2 + static let noteLabelTopInset = BKInset.inset4 + static let lowerLabelTopInset = BKInset.inset3 static let horizontalInset = BKInset.inset5 - static let contentSpacing = BKSpacing.spacing4 static let topInset = BKInset.inset5 static let bottomInset = BKInset.inset4 static let cornerRadius = BKRadius.medium - static let emotionImageSize: CGSize = CGSize(width: 32, height: 32) + static let lowerLabelHeight = 22 static let moreButtonSize: CGSize = CGSize(width: 20, height: 20) - static let imageCornerRadius: CGFloat = 20 } enum Constants { From f6c138d20dbee9af17a144d9c9328206de2ab7e1 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sun, 8 Feb 2026 23:01:01 +0900 Subject: [PATCH 06/21] =?UTF-8?q?[BOOK-499]=20feat:=20Colorsystem=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Extensions/UIColor+.swift | 13 +++++ .../ColorSystem/BKAtomicColor.swift | 54 +++++++++++++++---- .../ColorSystem/BKSemanticColor.swift | 35 ++++++++++-- .../BookDetail/Models/EmotionSeed.swift | 9 ++++ 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/src/Projects/BKDesign/Sources/Extensions/UIColor+.swift b/src/Projects/BKDesign/Sources/Extensions/UIColor+.swift index 1af7d98e..2a3983a6 100644 --- a/src/Projects/BKDesign/Sources/Extensions/UIColor+.swift +++ b/src/Projects/BKDesign/Sources/Extensions/UIColor+.swift @@ -127,6 +127,19 @@ public extension UIColor { } } + static func bkEmotionGraphTintColor( + _ semanticColor: BKSemanticColor.EmotionGraphTint + ) -> UIColor { + return UIColor { traitCollection in + switch traitCollection.userInterfaceStyle { + case .dark: + return semanticColor.resolve(for: .light) + default: + return semanticColor.resolve(for: .light) + } + } + } + static func bkShadowColor( _ semanticColor: BKSemanticColor.Shadow ) -> UIColor { diff --git a/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKAtomicColor.swift b/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKAtomicColor.swift index e408ff9a..97bdec7b 100644 --- a/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKAtomicColor.swift +++ b/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKAtomicColor.swift @@ -89,16 +89,50 @@ public enum BKAtomicColor { // Blue Palette public enum Blue: String { - case b50 = "#e3f4ff" - case b100 = "#bbe2ff" - case b200 = "#8dd0ff" - case b300 = "#56bdff" - case b400 = "#1dadff" - case b500 = "#009eff" - case b600 = "#008fff" - case b700 = "#007bff" - case b800 = "#1269ec" - case b900 = "#1f47cd" + case b50 = "#EBF3FF" + case b100 = "#C0D8FF" + case b200 = "#94BDFF" + case b300 = "#68A3FF" + case b400 = "#3C88FF" + case b500 = "#2A74E9" + case b600 = "#195CC7" + case b700 = "#0B47A5" + case b800 = "#013383" + case b900 = "#002661" + + public var color: UIColor { + return UIColor(hex: self.rawValue) + } + } + + public enum Orange: String { + case o50 = "#FFF1EB" + case o100 = "#FFD2BE" + case o200 = "#FFB392" + case o300 = "#FF9365" + case o400 = "#EF6D35" + case o500 = "#CD5622" + case o600 = "#AB4114" + case o700 = "#892F08" + case o800 = "#672001" + case o900 = "#451500" + + public var color: UIColor { + return UIColor(hex: self.rawValue) + } + } + + public enum Violet: String { + case v50 = "#F7F0FF" + case v100 = "#E6CEFF" + case v200 = "#D4ADFF" + case v300 = "#C38CFF" + case v400 = "#B26AFF" + case v500 = "#9A55E4" + case v600 = "#7F40C2" + case v700 = "#652EA0" + case v800 = "#4C1E7E" + case v900 = "#36125C" public var color: UIColor { return UIColor(hex: self.rawValue) diff --git a/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift b/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift index c9e12323..cd7bbe1a 100644 --- a/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift +++ b/src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift @@ -129,22 +129,24 @@ public enum BKSemanticColor { case joy case insight case sadness + case etc public func resolve(for mode: BKColorMode) -> UIColor { switch mode { case .light: switch self { - case .warmth: return UIColor(hex: "#E3931B") - case .joy: return UIColor(hex: "#EE6B33") - case .insight: return UIColor(hex: "#9A55E4") - case .sadness: return UIColor(hex: "#2872E9") + case .warmth: return BKAtomicColor.Yellow.y700.color + case .joy: return BKAtomicColor.Orange.o400.color + case .insight: return BKAtomicColor.Violet.v500.color + case .sadness: return BKAtomicColor.Blue.b500.color + case .etc: return .bkContentColor(.secondary) } // case .dark: // switch self { /* dark mode colors */ } } } } - + public enum EmotionBase { case warmth case joy @@ -166,6 +168,29 @@ public enum BKSemanticColor { } } + public enum EmotionGraphTint { + case warmth + case joy + case insight + case sadness + case etc + + public func resolve(for mode: BKColorMode) -> UIColor { + switch mode { + case .light: + switch self { + case .warmth: return BKAtomicColor.Yellow.y300.color + case .joy: return BKAtomicColor.Orange.o300.color + case .insight: return BKAtomicColor.Violet.v300.color + case .sadness: return BKAtomicColor.Blue.b300.color + case .etc: return BKAtomicColor.Neutral.n300.color + } + // case .dark: + // switch self { /* dark mode colors */ } + } + } + } + public enum Shadow { case primary diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift index 02ae94a6..e92b9721 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift @@ -47,6 +47,15 @@ enum EmotionSeed: String, CaseIterable { } } + var graphTintColor: UIColor { + switch self { + case .warmth: return .bkEmotionGraphTintColor(.warmth) + case .joy: return .bkEmotionGraphTintColor(.joy) + case .insight: return .bkEmotionGraphTintColor(.insight) + case .sad: return .bkEmotionGraphTintColor(.sadness) + } + } + static func from(emotion: Emotion) -> Self { switch emotion { case .joy: return .joy From 91c05ae40907bcfbb2e872a8a8186910025a2b50 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:44:45 +0900 Subject: [PATCH 07/21] =?UTF-8?q?[BOOK-499]=20feat:=20SeedGraphView(progre?= =?UTF-8?q?ss=20bar)=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookDetail/View/BookDetailView.swift | 3 +- .../BookDetail/View/SeedGraphView.swift | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift index 08566cba..9d224512 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift @@ -239,7 +239,8 @@ final class BookDetailView: BaseView { } func applySeedReport(with seeds: [Seed]) { - seedReportView.applyReport(with: seeds) + seedReportView.setEmotionHeader(with: Emotion.joy) + seedReportView.applyGraph(with: seeds) } func applySort(option: SortOption) { diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift new file mode 100644 index 00000000..f9aecc60 --- /dev/null +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift @@ -0,0 +1,59 @@ +// Copyright © 2026 Booket. All rights reserved + +import BKDesign +import BKDomain +import SnapKit +import UIKit + +final class SeedGraphView: BaseView { + private let stackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.distribution = .fill + stackView.alignment = .fill + stackView.spacing = 0 + stackView.clipsToBounds = true + stackView.layer.cornerRadius = 6 + return stackView + }() + + override func setupView() { + addSubview(stackView) + } + + override func setupLayout() { + stackView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } + + func applyGraph(with seeds: [Seed]) { + stackView.arrangedSubviews.forEach { + stackView.removeArrangedSubview($0) + $0.removeFromSuperview() + } + + let totalCount = CGFloat(seeds.reduce(0) { $0 + $1.count }) + + guard totalCount > 0 else { return } + + for (index, seed) in seeds.enumerated() { + let segment = UIView() + let emotion = EmotionSeed.from(seed: seed) + + segment.backgroundColor = emotion?.graphTintColor ?? .lightGray + stackView.addArrangedSubview(segment) + + segment.snp.makeConstraints { + let ratio = CGFloat(seed.count) / totalCount + + if index < seeds.count - 1 { + $0.width.equalTo(stackView.snp.width).multipliedBy(ratio) + } + } + } + + self.layoutIfNeeded() + } + +} From c9fe268c9deef8352c66d14161143444dc78f026 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:30:45 +0900 Subject: [PATCH 08/21] =?UTF-8?q?[BOOK-499]=20feat:=20SeedItemView=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookDetail/View/SeedItemView.swift | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift new file mode 100644 index 00000000..981ea4eb --- /dev/null +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift @@ -0,0 +1,75 @@ +// Copyright © 2026 Booket. All rights reserved + +import BKDesign +import BKDomain +import SnapKit +import UIKit + +final class SeedItemView: BaseView { + // MARK: - UI Components + private let dotView: UIView = { + let view = UIView() + view.layer.cornerRadius = LayoutConstants.dotRadius + return view + }() + + private let nameLabel = BKLabel( + fontStyle: .label2(weight: .regular), + color: .bkContentColor(.secondary), + alignment: .center + ) + + private let countLabel = BKLabel( + fontStyle: .caption1(weight: .regular), + color: .bkContentColor(.tertiary), + alignment: .center + ) + + override func setupView() { + addSubviews(dotView, nameLabel, countLabel) + } + + override func configure() { + backgroundColor = .bkBaseColor(.primary) + layer.cornerRadius = LayoutConstants.bgRadius + clipsToBounds = true + } + + override func setupLayout() { + dotView.snp.makeConstraints { + $0.top.equalToSuperview().inset(LayoutConstants.dotToTopInset) + $0.centerX.equalToSuperview() + $0.size.equalTo(LayoutConstants.dotSize) + } + + nameLabel.snp.makeConstraints { + $0.top.equalTo(dotView.snp.bottom).offset(LayoutConstants.nameToDot) + $0.centerX.equalToSuperview() + } + + countLabel.snp.makeConstraints { + $0.top.equalTo(nameLabel.snp.bottom) + $0.centerX.equalToSuperview() + $0.bottom.equalToSuperview().inset(LayoutConstants.countLabelBottomInset) + } + } + + func configure(with seed: Seed) { + let emotion = EmotionSeed.from(seed: seed) + dotView.backgroundColor = emotion?.graphTintColor + nameLabel.setText(text: seed.name) + countLabel.setText(text: "\(seed.count)개") + } +} + +private extension SeedItemView { + enum LayoutConstants { + static let dotRadius = BKRadius.xsmall + static let bgRadius = BKRadius.medium + static let dotToTopInset = BKSpacing.spacing3 + static let dotSize = CGSize(width: 10, height: 10) + + static let nameToDot = BKSpacing.spacing2 + static let countLabelBottomInset = BKSpacing.spacing2 + } +} From fbd54e34a1bb93032a220e19e0dd0d2ef1718339 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 12:50:34 +0900 Subject: [PATCH 09/21] =?UTF-8?q?[BOOK-499]=20feat:=20SeedReportView=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=20=EB=B7=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookDetail/View/SeedReportView.swift | 264 +++++++++--------- 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift index 2140d941..5fc93ef6 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift @@ -6,189 +6,189 @@ import SnapKit import UIKit final class SeedReportView: BaseView { - private let titleLabel = BKLabel( - text: "내가 모은 씨앗", - fontStyle: .body2(weight: .medium), - color: .bkContentColor(.secondary) - ) + // MARK: - Properties + private var isExpanded = false - private var emotionReport: UIStackView = { + // MARK: - UI Components + private let containerStackView: UIStackView = { let stackView = UIStackView() - stackView.axis = .horizontal - stackView.distribution = .equalSpacing + stackView.axis = .vertical + stackView.spacing = 16 stackView.alignment = .fill return stackView }() + private let headerView = UIView() + private let emotionImageView = UIImageView() + private let reportLabel = BKLabel2( - fontStyle: .label2(weight: .regular), + fontStyle: .label1(weight: .medium), color: .bkContentColor(.secondary), highlightColor: .bkContentColor(.brand), - highlightFont: BKTextStyle.label2(weight: .semiBold).uiFont + highlightFont: BKTextStyle.label1(weight: .semiBold).uiFont ) - private let reportContainer = UIView() + private let foldButton: UIImageView = { + let imageView = UIImageView( + image: BKImage.Icon.chevronDown + .withRenderingMode(.alwaysTemplate) + ) + imageView.tintColor = .bkContentColor(.tertiary) + imageView.isUserInteractionEnabled = true + return imageView + }() + + private let divider = BKDivider(type: .small) + + private let expandedView: UIView = { + let view = UIView() + view.isHidden = true + view.alpha = 0 + return view + }() + + private let graphView = SeedGraphView() + + private let labelsStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.distribution = .fillEqually + stackView.alignment = .fill + stackView.spacing = 4 + return stackView + }() override func setupView() { - addSubviews(titleLabel, emotionReport, reportContainer) - reportContainer.addSubview(reportLabel) + addSubview(containerStackView) + + headerView.addSubviews(emotionImageView, reportLabel, foldButton) + [headerView, expandedView].forEach(containerStackView.addArrangedSubview) + expandedView.addSubviews(divider, graphView, labelsStackView) + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggleExpansion)) + foldButton.addGestureRecognizer(tapGesture) } override func configure() { layer.cornerRadius = LayoutConstants.cornerRadius clipsToBounds = true backgroundColor = .bkBaseColor(.secondary) - reportContainer.backgroundColor = .bkBaseColor(.primary) - reportContainer.layer.borderWidth = LayoutConstants.reportContainerBorderWidth - reportContainer.layer.cornerRadius = LayoutConstants.reportContainerCornerRadius - reportContainer.layer.borderColor = UIColor.bkBorderColor(.primary).cgColor - reportContainer.clipsToBounds = true + + emotionImageView.image = BKImage.Graphics.warmCircle + reportLabel.setText(text: "테스트용 텍스트입니다.") } override func setupLayout() { - titleLabel.snp.makeConstraints { - $0.top.trailing.leading.equalToSuperview() - .inset(LayoutConstants.contentInset) + containerStackView.snp.makeConstraints { + $0.edges.equalToSuperview().inset(LayoutConstants.contentInset) } - emotionReport.snp.makeConstraints { - $0.top.equalTo(titleLabel.snp.bottom) - .offset(LayoutConstants.contentSpacing) - $0.height.equalTo(LayoutConstants.emotionReportHeight) - $0.leading.trailing.equalToSuperview() - .inset(LayoutConstants.contentInset * 2) + headerView.snp.makeConstraints { + $0.height.equalTo(LayoutConstants.emotionStackHeight) } - reportContainer.snp.makeConstraints { - $0.top.equalTo(emotionReport.snp.bottom) - .offset(LayoutConstants.contentSpacing) - $0.leading.trailing.bottom.equalToSuperview() - .inset(LayoutConstants.contentInset) - $0.height.equalTo(42) + emotionImageView.snp.makeConstraints { + $0.leading.equalToSuperview() + $0.centerY.equalToSuperview() + $0.size.equalTo( + CGSize( + width: LayoutConstants.emotionStackHeight, + height: LayoutConstants.emotionStackHeight + ) + ) } reportLabel.snp.makeConstraints { - $0.center.equalToSuperview() + $0.leading + .equalTo(emotionImageView.snp.trailing) + .offset(LayoutConstants.labelLeadingInset) + $0.centerY.equalToSuperview() } - } - - func applyReport(with seeds: [Seed]) { - var counts: [EmotionSeed: Int] = [:] - for s in seeds { - if let key = EmotionSeed.from(seed: s) { - counts[key, default: 0] += s.count - } - } - applyReportCore(counts: counts) - } -} - -private extension SeedReportView { - func applyReportCore(counts: [EmotionSeed: Int]) { - emotionReport.arrangedSubviews.forEach { - emotionReport.removeArrangedSubview($0) - $0.removeFromSuperview() + + foldButton.snp.makeConstraints { + $0.trailing.equalToSuperview() + $0.centerY.equalToSuperview() + $0.size.equalTo(LayoutConstants.iconSize) } - - for seed in EmotionSeed.allCases { - let count = counts[seed] ?? 0 - emotionReport.addArrangedSubview(makeInnerView(with: seed, count: count)) + + divider.snp.makeConstraints { + $0.top.horizontalEdges.equalToSuperview() } - - let (summary, highlightedWord) = generateEmotionSummary(from: counts) - reportLabel.setText(text: summary) - reportLabel.highlightedWord = highlightedWord - } - - func generateEmotionSummary( - from counts: [EmotionSeed: Int] - ) -> (String, String) { - let sorted = EmotionSeed.allCases - .map { ($0, counts[$0] ?? 0) } - .sorted { $0.1 > $1.1 } - guard let maxCount = sorted.first?.1, maxCount > 0 else { - return ("감정 데이터가 부족해요.", "") + graphView.snp.makeConstraints { + $0.top.equalTo(divider.snp.bottom).offset(LayoutConstants.graphTopOffset) + $0.horizontalEdges.equalToSuperview() + $0.height.equalTo(LayoutConstants.graphHeight) } - let top = sorted.filter { $0.1 == maxCount }.map { $0.0 } - if top.count >= 3 { - return ("이 책에서 여러 감정이 고르게 담겼어요", "여러 감정이 고르게 담겼어요") - } else { - let names = top.map { $0.rawValue }.joined(separator: ", ") - return ("이 책에서 \(names) 감정을 많이 느꼈어요", names) + labelsStackView.snp.makeConstraints { + $0.top.equalTo(graphView.snp.bottom).offset(LayoutConstants.labelsTopOffset) + $0.height.equalTo(72) + $0.horizontalEdges.equalToSuperview() + $0.bottom.equalToSuperview() } } - func makeInnerView( - with emotion: EmotionSeed, - count: Int - ) -> UIView { - let containerView = UIView() - let imageView = UIImageView(image: emotion.image) - let labelContainer = UIView() - let emotionLabel = BKLabel( - text: emotion.rawValue, - fontStyle: .label2(weight: .semiBold), - color: emotion.color - ) - labelContainer.backgroundColor = emotion.baseColor - labelContainer.layer.cornerRadius = LayoutConstants.labelContainerCornerRadius - labelContainer.clipsToBounds = true - let countLabel = BKLabel( - text: "\(count)", - fontStyle: .label2(weight: .regular), - color: .bkContentColor(.secondary) - ) - - containerView.addSubviews(imageView, labelContainer, countLabel) - labelContainer.addSubview(emotionLabel) + func setEmotionHeader(with emotion: Emotion) { + let emotion = EmotionSeed.from(emotion: emotion) + let emotionText = "\'\(emotion.rawValue)\'" + emotionImageView.image = emotion.circleImage + reportLabel.highlightColor = emotion.color + reportLabel.setText(text: "\(emotionText) 감정을 많이 느꼈어요") + reportLabel.highlightedWord = emotionText + } + + func applyGraph(with seeds: [Seed]) { + graphView.applyGraph(with: seeds) - imageView.snp.makeConstraints { - $0.top.leading.trailing.equalToSuperview() - $0.size.equalTo(LayoutConstants.imageSize) + labelsStackView.arrangedSubviews.forEach { + $0.removeFromSuperview() } + print(seeds) + let seedDictionary = Dictionary(uniqueKeysWithValues: seeds.map { ($0.name, $0) }) + print(seedDictionary) - labelContainer.snp.makeConstraints { - $0.top.equalTo(imageView.snp.bottom) - .offset(LayoutConstants.labelContainerOffset) - $0.height.equalTo(LayoutConstants.labelContainerHeight) - $0.centerX.equalToSuperview() + EmotionSeed.allCases.forEach { emotionCase in + seeds.forEach { seed in + if seed.name == emotionCase.rawValue && seed.count >= 1 { + let itemView = SeedItemView() + itemView.configure(with: seed) + labelsStackView.addArrangedSubview(itemView) + } + } } - emotionLabel.snp.makeConstraints { - $0.horizontalEdges.equalToSuperview() - .inset(LayoutConstants.emotionLabelHorizontalInset) - $0.verticalEdges.equalToSuperview() - .inset(LayoutConstants.emotionLabelVerticalInset) - } + self.setNeedsLayout() + self.layoutIfNeeded() + } +} + +private extension SeedReportView { + @objc private func toggleExpansion() { + isExpanded.toggle() - countLabel.snp.makeConstraints { - $0.top.equalTo(labelContainer.snp.bottom) - .offset(LayoutConstants.countLabelOffset) - $0.centerX.equalToSuperview() - $0.bottom.equalToSuperview() + UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseInOut]) { + self.expandedView.isHidden = !self.isExpanded + self.expandedView.alpha = self.isExpanded ? 1 : 0 + + let angle: CGFloat = self.isExpanded ? .pi : 0 + self.foldButton.transform = CGAffineTransform(rotationAngle: angle) + + self.layoutIfNeeded() } - - return containerView } } private extension SeedReportView { enum LayoutConstants { static let contentInset = BKInset.inset4 - static let contentSpacing = BKSpacing.spacing5 static let cornerRadius = BKRadius.medium - static let reportLabelVerticalInset = BKInset.inset3 - static let reportContainerBorderWidth = BKBorder.border1 - static let reportContainerCornerRadius = BKRadius.small - static let labelContainerHeight: CGFloat = 24 - static let labelContainerCornerRadius: CGFloat = labelContainerHeight / 2 - static let imageSize: CGSize = CGSize(width: 50, height: 50) - static let labelContainerOffset = BKInset.inset2 - static let countLabelOffset = BKInset.inset1 - static let emotionLabelHorizontalInset = BKInset.inset2 - static let emotionLabelVerticalInset = BKInset.inset1 - static let emotionReportHeight: CGFloat = 106 + static let emotionStackHeight = 36 + static let labelLeadingInset = BKSpacing.spacing2 + static let iconSize: CGSize = CGSize(width: 24, height: 24) + + static let graphHeight: CGFloat = 12 + static let graphTopOffset: CGFloat = BKSpacing.spacing5 + static let labelsTopOffset: CGFloat = BKSpacing.spacing4 } } From 3aaa79876f6ba81694a519e5256dd28d95237818 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:27:18 +0900 Subject: [PATCH 10/21] [BOOK-499] feat: add api-v2 base url --- src/Projects/BKData/Sources/Constant/APIConfig.swift | 7 +++++++ src/SupportingFiles/Booket/Info.plist | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/Projects/BKData/Sources/Constant/APIConfig.swift b/src/Projects/BKData/Sources/Constant/APIConfig.swift index 9b882d8d..b26a1136 100644 --- a/src/Projects/BKData/Sources/Constant/APIConfig.swift +++ b/src/Projects/BKData/Sources/Constant/APIConfig.swift @@ -13,4 +13,11 @@ enum APIConfig { } return value }() + + static let baseV2URL: String = { + guard let value = bundle.object(forInfoDictionaryKey: "BASE_API_V2_URL") as? String else { + fatalError("Can't load environment: BKData.BASE_API_URL") + } + return value + }() } diff --git a/src/SupportingFiles/Booket/Info.plist b/src/SupportingFiles/Booket/Info.plist index 607cf91b..4fc2e21d 100644 --- a/src/SupportingFiles/Booket/Info.plist +++ b/src/SupportingFiles/Booket/Info.plist @@ -8,6 +8,10 @@ 문장 카드를 이미지로 저장하기 위해 사진첩 접근 권한이 필요합니다. BASE_API_URL $(BASE_API_URL) + BASE_API_V2_URL + $(BASE_API_V2_URL) + LSApplicationCategoryType + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable From d26e95cd4e0f22e36ce2fdf36c086a2e86906d9b Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:27:34 +0900 Subject: [PATCH 11/21] =?UTF-8?q?[BOOK-499]=20feat:=20etc=20emotion=20case?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Projects/BKDomain/Sources/Entity/Emotion.swift | 1 + .../MainFlow/BookDetail/Models/EmotionSeed.swift | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/Projects/BKDomain/Sources/Entity/Emotion.swift b/src/Projects/BKDomain/Sources/Entity/Emotion.swift index ebe70c95..9641d909 100644 --- a/src/Projects/BKDomain/Sources/Entity/Emotion.swift +++ b/src/Projects/BKDomain/Sources/Entity/Emotion.swift @@ -5,4 +5,5 @@ public enum Emotion: String, CaseIterable, Decodable { case joy = "즐거움" case sad = "슬픔" case insight = "깨달음" + case etc = "기타" } diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift index e92b9721..7581195b 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift @@ -10,6 +10,7 @@ enum EmotionSeed: String, CaseIterable { case joy = "즐거움" case sad = "슬픔" case insight = "깨달음" + case etc = "기타" var image: UIImage { switch self { @@ -17,6 +18,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return BKImage.Graphics.joy case .insight: return BKImage.Graphics.insight case .sad: return BKImage.Graphics.sad + case .etc: return BKImage.Graphics.sad } } @@ -26,6 +28,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return BKImage.Graphics.joyCircle case .sad: return BKImage.Graphics.sadCircle case .insight: return BKImage.Graphics.insightCircle + case .etc: return BKImage.Graphics.insightCircle } } @@ -35,6 +38,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return .bkEmotionColor(.joy) case .insight: return .bkEmotionColor(.insight) case .sad: return .bkEmotionColor(.sadness) + case .etc: return .bkEmotionColor(.etc) } } @@ -44,6 +48,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return .bkEmotionBaseColor(.joy) case .insight: return .bkEmotionBaseColor(.insight) case .sad: return .bkEmotionBaseColor(.sadness) + case .etc: return .bkEmotionColor(.etc) } } @@ -53,6 +58,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return .bkEmotionGraphTintColor(.joy) case .insight: return .bkEmotionGraphTintColor(.insight) case .sad: return .bkEmotionGraphTintColor(.sadness) + case .etc: return .bkEmotionGraphTintColor(.etc) } } @@ -62,6 +68,7 @@ enum EmotionSeed: String, CaseIterable { case .sad: return .sad case .insight: return .insight case .warmth: return .warmth + case .etc: return .etc } } @@ -71,6 +78,7 @@ enum EmotionSeed: String, CaseIterable { case "joy", "즐거움": return .joy case "sad", "슬픔": return .sad case "insight", "깨달음": return .insight + case "etc", "기타": return .etc default: return nil } } @@ -86,6 +94,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return BKImage.Graphics.joyCard case .insight: return BKImage.Graphics.insightCard case .sad: return BKImage.Graphics.sadCard + case .etc: return BKImage.Graphics.sadCard } } @@ -96,6 +105,7 @@ enum EmotionSeed: String, CaseIterable { case .joy: return UIColor(hex: "FFF7F5") case .insight: return UIColor(hex: "FBF8FF") case .sad: return UIColor(hex: "F4F8FF") + case .etc: return UIColor(hex: "F4F8FF") } } } From 8ef8f5e539ddfaf25ebdae2a721a7b4261b6f54d Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:17:31 +0900 Subject: [PATCH 12/21] =?UTF-8?q?[BOOK-499]=20feat:=20api-v2=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8A=94=20=EC=BC=80=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=EB=A7=8C=20=EB=94=B0=EB=A1=9C=20=EB=B6=84=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Projects/BKData/Sources/API/RecordAPI.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Projects/BKData/Sources/API/RecordAPI.swift b/src/Projects/BKData/Sources/API/RecordAPI.swift index ae729d56..4aaab2e7 100644 --- a/src/Projects/BKData/Sources/API/RecordAPI.swift +++ b/src/Projects/BKData/Sources/API/RecordAPI.swift @@ -14,7 +14,12 @@ enum RecordAPI { extension RecordAPI: RequestTarget { var baseURL: String { - return "\(APIConfig.baseURL)/reading-records" + switch self { + case .fetch, .seed: + return "\(APIConfig.baseV2URL)/reading-records" + default: + return "\(APIConfig.baseURL)/reading-records" + } } var path: String { From f27f584a1cb31b1649a62407e448b698a01bb8ff Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:17:49 +0900 Subject: [PATCH 13/21] =?UTF-8?q?[BOOK-499]=20feat:=20fetch,=20seed=20v2?= =?UTF-8?q?=20responseDTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Response/DetailRecordResponseDTO.swift | 36 +++++++++++++++++++ .../DTO/Response/FetchRecordResponseDTO.swift | 3 +- .../Response/PrimaryEmotionResponseDTO.swift | 13 +++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift diff --git a/src/Projects/BKData/Sources/DTO/Response/DetailRecordResponseDTO.swift b/src/Projects/BKData/Sources/DTO/Response/DetailRecordResponseDTO.swift index d0303ad5..cc64b1dd 100644 --- a/src/Projects/BKData/Sources/DTO/Response/DetailRecordResponseDTO.swift +++ b/src/Projects/BKData/Sources/DTO/Response/DetailRecordResponseDTO.swift @@ -36,3 +36,39 @@ extension DetailRecordResponseDTO { ) } } + +// api-v2 +public struct DetailRecordV2ResponseDTO: Decodable { + public let id: String + public let userBookId: String + public let pageNumber: Int + public let quote: String + public let review: String? + public let primaryEmotion: PrimaryEmotionResponseDTO + public let detailEmotions: [DetailEmotionResponseDTO?] + public let createdAt: String + public let updatedAt: String + public let bookTitle: String + public let bookPublisher: String + public let bookCoverImageUrl: URL + public let author: String +} + +extension DetailRecordV2ResponseDTO { + func toRecordInfo() -> RecordInfo { + return RecordInfo( + recordId: id, + bookId: userBookId, + pageNumber: pageNumber, + quote: quote, + review: review, + emotionTags: [primaryEmotion.displayName], + createdAt: DateParser.parseISO8601(createdAt) ?? .distantPast, + updatedAt: DateParser.parseISO8601(updatedAt), + bookTitle: bookTitle, + bookPublisher: bookPublisher, + bookCoverImageUrl: bookCoverImageUrl, + author: author + ) + } +} diff --git a/src/Projects/BKData/Sources/DTO/Response/FetchRecordResponseDTO.swift b/src/Projects/BKData/Sources/DTO/Response/FetchRecordResponseDTO.swift index 77400282..4739ccab 100644 --- a/src/Projects/BKData/Sources/DTO/Response/FetchRecordResponseDTO.swift +++ b/src/Projects/BKData/Sources/DTO/Response/FetchRecordResponseDTO.swift @@ -3,7 +3,8 @@ import BKDomain struct FetchRecordResponseDTO: Decodable { - let readingRecords: [DetailRecordResponseDTO] + let readingRecords: [DetailRecordV2ResponseDTO] let lastPage: Bool let totalResults: Int + let representativeEmotion: PrimaryEmotionResponseDTO? } diff --git a/src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift b/src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift new file mode 100644 index 00000000..d10ab8e3 --- /dev/null +++ b/src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift @@ -0,0 +1,13 @@ +// Copyright © 2026 Booket. All rights reserved + +import BKDomain + +public struct PrimaryEmotionResponseDTO: Decodable { + let code: String + let displayName: Emotion +} + +public struct DetailEmotionResponseDTO: Decodable { + let id: String + let name: String +} From 38d0ce38853574c2a554164c6d4053ff4370e07b Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:19:32 +0900 Subject: [PATCH 14/21] =?UTF-8?q?[BOOK-499]=20feat:=20fetch=20in=20RecordR?= =?UTF-8?q?epo=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20RecordFetchResult=20Enti?= =?UTF-8?q?ty=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/DefaultRecordRepository.swift | 11 ++++++++-- .../Sources/Entity/RecordFetchResult.swift | 22 +++++++++++++++++++ .../Repository/RecordRepository.swift | 2 +- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift diff --git a/src/Projects/BKData/Sources/Repository/DefaultRecordRepository.swift b/src/Projects/BKData/Sources/Repository/DefaultRecordRepository.swift index 2720d86c..2093ed2b 100644 --- a/src/Projects/BKData/Sources/Repository/DefaultRecordRepository.swift +++ b/src/Projects/BKData/Sources/Repository/DefaultRecordRepository.swift @@ -33,7 +33,7 @@ public final class DefaultRecordRepository: RecordRepository { bookId: String, sortType: LibrarySortType, page: Int - ) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError> { + ) -> AnyPublisher { networkProvider.request( target: RecordAPI.fetch( userBookId: bookId, @@ -46,7 +46,14 @@ public final class DefaultRecordRepository: RecordRepository { ) .mapError { $0.toDomainError() } .debugError(logger: AppLogger.network) - .map { ($0.readingRecords.map { $0.toRecordInfo() }, !$0.lastPage, $0.totalResults) } + .map { + RecordFetchResult( + infos: $0.readingRecords.map { $0.toRecordInfo() }, + hasMore: !$0.lastPage, + totalCount: $0.totalResults, + mainEmotion: $0.representativeEmotion?.displayName + ) + } .eraseToAnyPublisher() } diff --git a/src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift b/src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift new file mode 100644 index 00000000..7dae726f --- /dev/null +++ b/src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift @@ -0,0 +1,22 @@ +// Copyright © 2026 Booket. All rights reserved + +import Foundation + +public struct RecordFetchResult { + public let infos: [RecordInfo] + public let hasMore: Bool + public let totalCount: Int + public let mainEmotion: Emotion? + + public init( + infos: [RecordInfo], + hasMore: Bool, + totalCount: Int, + mainEmotion: Emotion? + ) { + self.infos = infos + self.hasMore = hasMore + self.totalCount = totalCount + self.mainEmotion = mainEmotion + } +} diff --git a/src/Projects/BKDomain/Sources/Interface/Repository/RecordRepository.swift b/src/Projects/BKDomain/Sources/Interface/Repository/RecordRepository.swift index 5787bcc6..5654778f 100644 --- a/src/Projects/BKDomain/Sources/Interface/Repository/RecordRepository.swift +++ b/src/Projects/BKDomain/Sources/Interface/Repository/RecordRepository.swift @@ -13,7 +13,7 @@ public protocol RecordRepository { bookId: String, sortType: LibrarySortType, page: Int - ) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError> + ) -> AnyPublisher func findBy( id recordId: String From 76447894925fe5368f3de17ad27d5b808099709a Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:19:57 +0900 Subject: [PATCH 15/21] =?UTF-8?q?[BOOK-499]=20feat:=20FetchRecordsUseCase?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Interface/Usecase/FetchRecordsUseCase.swift | 2 +- .../BKDomain/Sources/UseCase/DefaultFetchRecordsUseCase.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Projects/BKDomain/Sources/Interface/Usecase/FetchRecordsUseCase.swift b/src/Projects/BKDomain/Sources/Interface/Usecase/FetchRecordsUseCase.swift index b0f0d602..ca813c9d 100644 --- a/src/Projects/BKDomain/Sources/Interface/Usecase/FetchRecordsUseCase.swift +++ b/src/Projects/BKDomain/Sources/Interface/Usecase/FetchRecordsUseCase.swift @@ -6,5 +6,5 @@ public protocol FetchRecordsUseCase { func execute( id: String, page: Int - ) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError> + ) -> AnyPublisher } diff --git a/src/Projects/BKDomain/Sources/UseCase/DefaultFetchRecordsUseCase.swift b/src/Projects/BKDomain/Sources/UseCase/DefaultFetchRecordsUseCase.swift index fcecb6b5..dbea511a 100644 --- a/src/Projects/BKDomain/Sources/UseCase/DefaultFetchRecordsUseCase.swift +++ b/src/Projects/BKDomain/Sources/UseCase/DefaultFetchRecordsUseCase.swift @@ -12,7 +12,7 @@ public struct DefaultFetchRecordsUseCase: FetchRecordsUseCase { public func execute( id: String, page: Int - ) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError> { + ) -> AnyPublisher { repository.fetch( bookId: id, sortType: .pageNumberDesc, From 124cf2a6242c6a148edca22f4958e7a1b5f2ad0d Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:20:20 +0900 Subject: [PATCH 16/21] =?UTF-8?q?[BOOK-499]=20feat:=20=EB=8C=80=ED=91=9C?= =?UTF-8?q?=EA=B0=90=EC=A0=95=20api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainFlow/BookDetail/View/BookDetailView.swift | 5 ++++- .../BookDetail/View/BookDetailViewController.swift | 9 +++++++++ .../BookDetail/ViewModel/BookDetailViewModel.swift | 14 +++++++++++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift index 9d224512..cbc24a48 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift @@ -238,8 +238,11 @@ final class BookDetailView: BaseView { } } + func applySeedHeader(with mainEmotion: Emotion) { + seedReportView.setEmotionHeader(with: mainEmotion) + } + func applySeedReport(with seeds: [Seed]) { - seedReportView.setEmotionHeader(with: Emotion.joy) seedReportView.applyGraph(with: seeds) } diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewController.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewController.swift index 5353b10e..c9818f60 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewController.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewController.swift @@ -214,6 +214,15 @@ final class BookDetailViewController: BaseViewController, Screen } .store(in: &cancellable) + viewModel.statePublisher + .receive(on: DispatchQueue.main) + .compactMap { $0.mainEmotion } + .removeDuplicates() + .sink { [weak self] in + self?.contentView.applySeedHeader(with: $0) + } + .store(in: &cancellable) + viewModel.statePublisher .map { $0.deleteCompleted } .removeDuplicates() diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/ViewModel/BookDetailViewModel.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/ViewModel/BookDetailViewModel.swift index 92116aa4..4d3e24a3 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/ViewModel/BookDetailViewModel.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/ViewModel/BookDetailViewModel.swift @@ -10,6 +10,7 @@ final class BookDetailViewModel: BaseViewModel { var items: [BookDetailItem] = [] var currentBook: Book? var sortOption: SortOption = .pageDescending + var mainEmotion: Emotion? var seeds = [Seed]() var isAddNoteTriggered = false var isStatusButtonTriggered = false @@ -40,7 +41,12 @@ final class BookDetailViewModel: BaseViewModel { case cellTapHandled case upsert(isbn: String, status: BookRegistrationStatus) case upsertSuccessed(Book) - case fetchRecordsSuccessed(items: [BookDetailItem], hasMore: Bool, totalResult: Int) + case fetchRecordsSuccessed( + items: [BookDetailItem], + hasMore: Bool, + totalResult: Int, + mainEmotion: Emotion? + ) case fetchSeedStatsSuccessed([Seed]) case fetchBookDetailSuccessed(Book) case errorOccured(DomainError) @@ -134,11 +140,12 @@ final class BookDetailViewModel: BaseViewModel { case .fetchBookDetailSuccessed(let book): newState.currentBook = book - case .fetchRecordsSuccessed(let items, let hasMore, let totalResults): + case .fetchRecordsSuccessed(let items, let hasMore, let totalResults, let mainEmotion): newState.items = items newState.nextPage = 1 newState.hasMore = hasMore newState.totalResults = totalResults + newState.mainEmotion = mainEmotion case .fetchSeedStatsSuccessed(let seeds): newState.seeds = seeds @@ -246,7 +253,8 @@ final class BookDetailViewModel: BaseViewModel { return page == 0 ? Action.fetchRecordsSuccessed( items: items, hasMore: $0.hasMore, - totalResult: $0.totalCount + totalResult: $0.totalCount, + mainEmotion: $0.mainEmotion ) : Action.appendRecordsSuccessed( items: items, hasMore: $0.hasMore From ad31bd2c09336381c1acd7e26a2647d0aa031ab3 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:20:51 +0900 Subject: [PATCH 17/21] =?UTF-8?q?[BOOK-499]=20fix:=20Emotion=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=ED=95=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 추후 지용님 작업 내역과 merge 예정 --- .../Sources/MainFlow/Note/View/EmotionRegistrationView.swift | 4 ++++ .../MainFlow/NoteCompletion/View/AppreciationResultView.swift | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift b/src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift index c7b01866..3834a087 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift @@ -23,6 +23,8 @@ extension Emotion { imageView.image = BKImage.Graphics.sadEmotion case .insight: imageView.image = BKImage.Graphics.insightEmotion + default: + imageView.image = BKImage.Graphics.warmEmotion } imageView.layer.cornerRadius = 12 @@ -154,6 +156,8 @@ private extension EmotionRegistrationView { imageView.image = BKImage.Graphics.sadEmotion case .insight: imageView.image = BKImage.Graphics.insightEmotion + default: + imageView.image = BKImage.Graphics.warmEmotion } imageView.layer.cornerRadius = 12 diff --git a/src/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift b/src/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift index 930a83e6..09afd71e 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift @@ -30,6 +30,8 @@ enum EmotionIcon: String { return .sadness case .insight: return .insight + default: + return .warmth } } } From 79bf7a9db18638cee49ecc5ea27742c7407cadf9 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:26:06 +0900 Subject: [PATCH 18/21] =?UTF-8?q?[BOOK-499]=20fix:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=B6=9C=EB=A0=A5=EB=AC=B8=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/MainFlow/BookDetail/View/SeedReportView.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift index 5fc93ef6..1f6ff7d9 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift @@ -144,9 +144,6 @@ final class SeedReportView: BaseView { labelsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } - print(seeds) - let seedDictionary = Dictionary(uniqueKeysWithValues: seeds.map { ($0.name, $0) }) - print(seedDictionary) EmotionSeed.allCases.forEach { emotionCase in seeds.forEach { seed in From 415d02143696d71fc123b06cd2278b6473e480d0 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:57:43 +0900 Subject: [PATCH 19/21] =?UTF-8?q?[BOOK-499]=20feat:=20=EC=84=A4=EB=AA=85?= =?UTF-8?q?=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20EmotionSeed=20case=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/MainFlow/BookDetail/Models/EmotionSeed.swift | 9 +++++++++ .../MainFlow/BookDetail/View/SeedReportView.swift | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift index 7581195b..e42a23dd 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift @@ -108,4 +108,13 @@ enum EmotionSeed: String, CaseIterable { case .etc: return UIColor(hex: "F4F8FF") } } + + var descriptionText: String { + switch self { + case .etc: + return "감정으로 문장만 기록했어요" + default: + return "감정을 많이 느꼈어요" + } + } } diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift index 1f6ff7d9..595111fc 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift @@ -134,7 +134,7 @@ final class SeedReportView: BaseView { let emotionText = "\'\(emotion.rawValue)\'" emotionImageView.image = emotion.circleImage reportLabel.highlightColor = emotion.color - reportLabel.setText(text: "\(emotionText) 감정을 많이 느꼈어요") + reportLabel.setText(text: "\(emotionText) \(emotion.descriptionText)") reportLabel.highlightedWord = emotionText } From ca5ce5de9bf9db4bb51e7d1244f7ffa9d9d4a003 Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:00:22 +0900 Subject: [PATCH 20/21] =?UTF-8?q?[BOOK-499]=20fix:=20codeRabbit=20review?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Projects/BKData/Sources/Constant/APIConfig.swift | 2 +- .../Sources/MainFlow/BookDetail/View/SeedReportView.swift | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Projects/BKData/Sources/Constant/APIConfig.swift b/src/Projects/BKData/Sources/Constant/APIConfig.swift index b26a1136..561d71d3 100644 --- a/src/Projects/BKData/Sources/Constant/APIConfig.swift +++ b/src/Projects/BKData/Sources/Constant/APIConfig.swift @@ -16,7 +16,7 @@ enum APIConfig { static let baseV2URL: String = { guard let value = bundle.object(forInfoDictionaryKey: "BASE_API_V2_URL") as? String else { - fatalError("Can't load environment: BKData.BASE_API_URL") + fatalError("Can't load environment: BKData.BASE_API_V2_URL") } return value }() diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift index 595111fc..13c1cf60 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift @@ -73,9 +73,6 @@ final class SeedReportView: BaseView { layer.cornerRadius = LayoutConstants.cornerRadius clipsToBounds = true backgroundColor = .bkBaseColor(.secondary) - - emotionImageView.image = BKImage.Graphics.warmCircle - reportLabel.setText(text: "테스트용 텍스트입니다.") } override func setupLayout() { From 131c1acde682eab0483b9d21174387e037c0c05d Mon Sep 17 00:00:00 2001 From: doyeonk429 <80318425+doyeonk429@users.noreply.github.com> Date: Sat, 14 Feb 2026 13:49:15 +0900 Subject: [PATCH 21/21] =?UTF-8?q?[BOOK-499]=20fix:=20peer=20Review=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainFlow/BookDetail/View/SeedReportView.swift | 12 ++++++------ src/SupportingFiles/Booket/Info.plist | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift index 13c1cf60..89ddbf90 100644 --- a/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift +++ b/src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift @@ -142,13 +142,13 @@ final class SeedReportView: BaseView { $0.removeFromSuperview() } + let seedDict = Dictionary(seeds.map { ($0.name, $0) }, uniquingKeysWith: { first, last in last }) + EmotionSeed.allCases.forEach { emotionCase in - seeds.forEach { seed in - if seed.name == emotionCase.rawValue && seed.count >= 1 { - let itemView = SeedItemView() - itemView.configure(with: seed) - labelsStackView.addArrangedSubview(itemView) - } + if let seed = seedDict[emotionCase.rawValue], seed.count >= 1 { + let itemView = SeedItemView() + itemView.configure(with: seed) + labelsStackView.addArrangedSubview(itemView) } } diff --git a/src/SupportingFiles/Booket/Info.plist b/src/SupportingFiles/Booket/Info.plist index 4fc2e21d..79750d62 100644 --- a/src/SupportingFiles/Booket/Info.plist +++ b/src/SupportingFiles/Booket/Info.plist @@ -10,8 +10,6 @@ $(BASE_API_URL) BASE_API_V2_URL $(BASE_API_V2_URL) - LSApplicationCategoryType - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable