Skip to content

Commit

Permalink
[refactor] NoteDetailCell 및 ViewModel 구현 #291
Browse files Browse the repository at this point in the history
  • Loading branch information
skkimeo committed Jun 24, 2023
1 parent 14d90f6 commit 754572f
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 19 deletions.
8 changes: 8 additions & 0 deletions Happiggy-bank/Happiggy-bank.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
A46B111128146188004AB185 /* Cafe24SsurroundAir.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A46B111028146188004AB185 /* Cafe24SsurroundAir.ttf */; };
A46B11122814618C004AB185 /* Cafe24Ssurround.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A46B110F28146181004AB185 /* Cafe24Ssurround.ttf */; };
A46B2E7729B493D7006A7870 /* LabeledCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46B2E7629B493D7006A7870 /* LabeledCollectionView.swift */; };
A46B2E7D29B5EB14006A7870 /* NoteDetailCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46B2E7C29B5EB14006A7870 /* NoteDetailCell.swift */; };
A46B2E7F29B5EB74006A7870 /* NoteDetailCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46B2E7E29B5EB74006A7870 /* NoteDetailCellViewModel.swift */; };
A46BC1EF2800626A00C2E5B4 /* TabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46BC1EE2800626A00C2E5B4 /* TabItem.swift */; };
A47D83462966C0C60028AA1D /* NotificationSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22ADF7E27F72F7300ECB77B /* NotificationSettingsViewModel.swift */; };
A47D83482966D3870028AA1D /* FontSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A47D83472966D3870028AA1D /* FontSelectionView.swift */; };
Expand Down Expand Up @@ -237,6 +239,8 @@
A46B110F28146181004AB185 /* Cafe24Ssurround.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Cafe24Ssurround.ttf; sourceTree = "<group>"; };
A46B111028146188004AB185 /* Cafe24SsurroundAir.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Cafe24SsurroundAir.ttf; sourceTree = "<group>"; };
A46B2E7629B493D7006A7870 /* LabeledCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabeledCollectionView.swift; sourceTree = "<group>"; };
A46B2E7C29B5EB14006A7870 /* NoteDetailCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteDetailCell.swift; sourceTree = "<group>"; };
A46B2E7E29B5EB74006A7870 /* NoteDetailCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteDetailCellViewModel.swift; sourceTree = "<group>"; };
A46BC1EE2800626A00C2E5B4 /* TabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItem.swift; sourceTree = "<group>"; };
A47D83472966D3870028AA1D /* FontSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSelectionView.swift; sourceTree = "<group>"; };
A47D8349296716BF0028AA1D /* FontCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -455,6 +459,7 @@
A4450C0D2966AF7D0088CC2C /* ViewModel */ = {
isa = PBXGroup;
children = (
A46B2E7E29B5EB74006A7870 /* NoteDetailCellViewModel.swift */,
);
path = ViewModel;
sourceTree = "<group>";
Expand Down Expand Up @@ -628,6 +633,7 @@
A896FBDA2966B1BC00A3400B /* View */ = {
isa = PBXGroup;
children = (
A46B2E7C29B5EB14006A7870 /* NoteDetailCell.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -1381,6 +1387,7 @@
A4569CBE28105052001E3FD6 /* CustomerServiceViewModel.swift in Sources */,
A8F985E0296FDE6000E5ACC6 /* ListTabViewController.swift in Sources */,
D284A5DE27FF3EFB00D20699 /* BottleNameEditViewController.swift in Sources */,
A46B2E7F29B5EB74006A7870 /* NoteDetailCellViewModel.swift in Sources */,
A466A31C28029D7400D655F4 /* UIAlertController+BasicFormat.swift in Sources */,
A8509E6E27C89A1200855153 /* UIColor+Extension.swift in Sources */,
D236DB8827FDD66900D7B8F0 /* NewBottleMessageFieldViewController.swift in Sources */,
Expand Down Expand Up @@ -1464,6 +1471,7 @@
A4F5714927DA589100E7DF9B /* NoteDatePickerData.swift in Sources */,
A484A329296004D200A58312 /* Subscriber.swift in Sources */,
A484A31E295D7B1400A58312 /* HTTPMethod.swift in Sources */,
A46B2E7D29B5EB14006A7870 /* NoteDetailCell.swift in Sources */,
D2C48BFF27E9D60A006FC59E /* Gravity.swift in Sources */,
A8EB5E8B27C8B087005704F2 /* UIButton+Extension.swift in Sources */,
A843331F27DA013800A12A54 /* NewBottleNameFieldViewController.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Happiggy-bank/Happiggy-bank/Base/UI/View/BaseButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ final class BaseButton: UIButton {

// MARK: - Properties

var customFont: CustomFont?
private let fontManager: FontPublishing = FontManager.shared
private var cancellable: AnyCancellable?
private var customFont: CustomFont?


// MARK: - Inits
Expand Down
4 changes: 2 additions & 2 deletions Happiggy-bank/Happiggy-bank/Base/UI/View/BaseLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import UIKit
final class BaseLabel: UILabel {

// MARK: - Properties


var customFont: CustomFont?
private let fontManager: FontPublishing = FontManager.shared
private var cancellable: AnyCancellable?
private var customFont: CustomFont?


// MARK: - Inits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ final class BaseTextField: UITextField {

// MARK: - Properties

var customFont: CustomFont?
private let fontManager: FontPublishing = FontManager.shared
private var cancellable: AnyCancellable?
private var customFont: CustomFont?


// MARK: - Inits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ final class BaseTextView: UITextView {

// MARK: - Properties

var customFont: CustomFont?
private let fontManager: FontPublishing = FontManager.shared
private var cancellable: AnyCancellable?
private var customFont: CustomFont?


// MARK: - Inits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ final class NewNoteDatePickerViewModel {
.customFormatted(type: .spaceAndDotWithDayOfWeek)
.nsMutableAttributedStringify()
.color(color: color)
.bold(
targetString: source.date.monthDotDayWithDayOfWeekString,
fontSize: Font.dateLabelFontSize
)
.bold(targetString: source.date.monthDotDayWithDayOfWeekString)
}

/// 쪽지 에셋 이미지 리턴
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ final class NewNoteTextViewModel {
self.newNote.date
.yearString
.nsMutableAttributedStringify()
.bold(fontSize: Font.secondaryText)
.bold()
}

/// 색깔 적용한 월, 일 텍스트
private var attributedMonthDayString: NSMutableAttributedString {
self.newNote.date
Expand All @@ -74,7 +74,7 @@ final class NewNoteTextViewModel {

let countString = "\(count)"
.nsMutableAttributedStringify()
.bold(fontSize: Font.secondaryText)
.bold()
.color(color: color)

countString.append(StringLiteral.letterCountText.nsMutableAttributedStringify())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//
// NoteDetailCell.swift
// Happiggy-bank
//
// Created by sun on 2023/03/06.
//

import UIKit

import SnapKit
import Then

/// NoteDetailList에서 사용하는 쪽지의 세부 내용을 확인할 수 있는 컬렉션 뷰 셀
///
/// viewModel 변수를 설정하면 해당 viewModel이 담고 있는 데이터에 맞게 UI 요소들을 업데이트함
final class NoteDetailCell: UICollectionViewCell {

// MARK: - Properties

/// 새로운 인스턴스를 지정하면 UI 요소들이 바로 업데이트 됨
var viewModel: NoteDetailCellViewModel? {
didSet { self.render() }
}

/// 작성 날짜 레이블
private let dateLabel = BaseLabel().then {
$0.changeFontSize(to: FontSize.secondaryLabel)
}

/// 몇 번째 쪽지인지 나타내는 레이블
private let indexLabel = BaseLabel().then {
$0.changeFontSize(to: FontSize.secondaryLabel)
$0.setContentHuggingPriority(.defaultHigh, for: .horizontal)
}

/// 저장한 사진을 나타내는 이미지 뷰
private let photoView = UIImageView().then {
$0.contentMode = .scaleAspectFill
$0.clipsToBounds = true
$0.layer.cornerRadius = Metric.photoCornerRadius
$0.layer.borderWidth = Metric.photoBorderWidth
$0.layer.borderColor = UIColor.systemBackground.cgColor
$0.isUserInteractionEnabled = true
}

/// 내용 레이블
private let contentLabel = BaseLabel().then {
$0.changeFontSize(to: FontSize.body)
$0.lineBreakMode = .byWordWrapping
$0.numberOfLines = .zero
$0.textColor = .black
}

/// 날짜와 인덱스 레이블을 담고 있는 스택 뷰
private let dateAndIndexStack = UIStackView()

/// 배경 이미지 뷰
private let backgroundImageView = UIImageView().then {
$0.image = AssetImage.noteLine?.resizableImage(
withCapInsets: Metric.imageCapInsets,
resizingMode: .stretch
)
$0.autoresizingMask.update(with: [.flexibleWidth, .flexibleHeight])
}

/// 배경 이미지 뷰를 제외한 모든 UI 요소를 담고 있는 스택 뷰
private let contentStack = UIStackView().then {
$0.axis = .vertical
$0.spacing = Metric.spacing16
}


// MARK: - Init(s)

override init(frame: CGRect) {
super.init(frame: frame)

self.configureViews()
}

required init?(coder: NSCoder) {
super.init(coder: coder)

self.configureViews()
}


// MARK: - Life Cycle

override func prepareForReuse() {
super.prepareForReuse()

self.viewModel = nil
self.photoView.layer.borderColor = UIColor.systemBackground.cgColor
}


// MARK: - Functions

/// 셀의 내용을 채우는 메서드
private func render() {
self.contentView.backgroundColor = self.viewModel?.backgroundColor
self.backgroundImageView.tintColor = self.viewModel?.lineColor
self.dateLabel.attributedText = self.createAttributedDateString()
self.indexLabel.attributedText = self.createAttributedIndexString()
self.contentLabel.attributedText = self.viewModel?.contentString.nsMutableAttributedStringify()
self.contentLabel.configureParagraphStyle(font: self.contentLabel.font)
self.photoView.image = self.viewModel?.photo()
self.photoView.isHidden = self.viewModel?.hasPhoto != true
}

private func createAttributedDateString() -> NSAttributedString? {
guard let viewModel
else {
return nil
}

let customFont = (self.dateLabel.customFont ?? .current)
let fontSize = self.dateLabel.font.pointSize
let font = UIFont(name: customFont.regular, size: fontSize) ?? .systemFont(ofSize: fontSize)
let boldFont = UIFont(name: customFont.bold, size: fontSize) ?? .boldSystemFont(ofSize: fontSize)
let color = viewModel.textColor ?? .black

return "\(viewModel.yearString) \(viewModel.dateString)"
.nsMutableAttributedStringify()
.color(color: color)
.font(font)
.bold(font: boldFont, targetString: viewModel.yearString)
}

private func createAttributedIndexString() -> NSAttributedString? {
guard let viewModel
else {
return nil
}

let customFont = (self.dateLabel.customFont ?? .current)
let fontSize = self.dateLabel.font.pointSize
let font = UIFont(name: customFont.regular, size: fontSize) ?? .systemFont(ofSize: fontSize)
let boldFont = UIFont(name: customFont.bold, size: fontSize) ?? .boldSystemFont(ofSize: fontSize)
let color = viewModel.textColor ?? .black
let indexString = viewModel.index.description
let slashString = "/\(viewModel.numberOfTotalNotes)"

return "\(indexString)\(slashString)"
.nsMutableAttributedStringify()
.color(color: color)
.font(font)
.bold(font: boldFont, targetString: indexString)
}

/// 뷰 초기 설정
private func configureViews() {
self.configureViewHierarchy()
self.configureViewLayout()
self.configurePhotoView()
}

/// 하위 뷰 추가
private func configureViewHierarchy() {
self.contentView.addSubviews(self.backgroundImageView, self.contentStack)
let contentStackSubviews = [self.dateAndIndexStack, self.photoView, self.contentLabel]
self.contentStack.addArrangedSubviews(contentStackSubviews)
self.dateAndIndexStack.addArrangedSubviews(self.dateLabel, self.indexLabel)
}

/// 뷰 레이아웃 설정
private func configureViewLayout() {
self.contentStack.snp.makeConstraints {
$0.edges.equalTo(self.contentView).inset(Metric.spacing24)
}
self.backgroundImageView.frame = self.contentView.bounds
self.photoView.snp.makeConstraints {
$0.width.equalTo(photoView.snp.height).multipliedBy(CGFloat.one)
}
}

/// photoView에 tapGestureRecognizer 추가
private func configurePhotoView() {
let tapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: #selector(self.photoDidTap(_:))
)
self.photoView.addGestureRecognizer(tapGestureRecognizer)
}

/// 사진을 탭했을 때 호출
@objc private func photoDidTap(_ sender: UITapGestureRecognizer) {
guard let photo = self.photoView.image,
photo != .error ?? UIImage()
else {
return
}
self.viewModel?.photoDidTap?(photo)
}
}


// MARK: - Constants
fileprivate extension NoteDetailCell {

/// 상수
enum Metric {
static let photoCornerRadius: CGFloat = 8
static let photoBorderWidth: CGFloat = 1
static let spacing16: CGFloat = 16
static let spacing24: CGFloat = 24
static let imageCapInsets = UIEdgeInsets(
top: imageInset,
left: imageInset,
bottom: imageInset,
right: imageInset
)
private static let imageInset: CGFloat = 15
}
}
Loading

0 comments on commit 754572f

Please sign in to comment.