Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

새로운 책 만들기 - 프리뷰와 입력뷰 연결, 색 버튼 효과, 임시로직 추가 #54

Merged
merged 19 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import UIKit
import Combine

final class BookCreationViewController: UIViewController {
// MARK: - Constant
static let maxTitleLength = 10
// MARK: - Property
private let bookImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(resource: .pinkBook)
imageView.contentMode = .scaleAspectFit

return imageView
}()
private let bookView: MHBookCover = MHBookCover()
private let bookTitleTextField: UITextField = {
let textField = UITextField()
textField.font = UIFont.ownglyphBerry(size: 25)
textField.textColor = .black
textField.returnKeyType = .done
textField.autocorrectionType = .no
textField.autocapitalizationType = .none
textField.spellCheckingType = .no

var attributedText = AttributedString(stringLiteral: "책 제목을 입력하세요")
attributedText.font = UIFont.ownglyphBerry(size: 25)
Expand Down Expand Up @@ -59,13 +60,50 @@ final class BookCreationViewController: UIViewController {

return button
}()
private let colorButtonInnerShadow: CAShapeLayer = {
let shadowLayer = CAShapeLayer()
shadowLayer.cornerRadius = 15
shadowLayer.fillColor = nil
shadowLayer.masksToBounds = true

// 그림자 경로 생성
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowOpacity = 0.35
shadowLayer.shadowOffset = CGSize(width: 0, height: 4)
shadowLayer.shadowRadius = 3

return shadowLayer
}()
@Published
private var viewModel: BookCreationViewModel
private var cancellables: Set<AnyCancellable> = []

// MARK: - Initializer
init(viewModel: BookCreationViewModel) {
self.viewModel = viewModel

super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
viewModel = BookCreationViewModel()

super.init(coder: coder)
}

// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()

setup()
configureConstraints()
configureNavigationBar()
configureViewModelBinding()
Copy link
Collaborator

Choose a reason for hiding this comment

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

P3: 바인딩을 viewDidLoad가 아닌 viewWillAppear에서 해주신 이유가 있으신가요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

화면에 안보이면 바인딩을 중지하기 위해서입니다!

configureAction()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let currentColorButton = bookColorButtons[viewModel.currentColorNumber]
self.addInnerShadow(to: currentColorButton)
}

// MARK: - TouchEvent
Expand All @@ -75,15 +113,15 @@ final class BookCreationViewController: UIViewController {
super.touchesBegan(touches, with: event)
}

// MARK: - Setup & Configuration
// MARK: - Helper
private func setup() {
view.backgroundColor = .baseBackground
navigationController?.navigationBar.isHidden = false
bookTitleTextField.delegate = self
bookColorButtons.last?.isUserInteractionEnabled = false // 마지막 버튼은 크기 조절을 위한 것
}

private func configureConstraints() {
// 책 미리보기
let bookPreviewViewBackground = bookImageView.embededInDefaultBackground(
let bookPreviewViewBackground = bookView.embededInDefaultBackground(
with: UIEdgeInsets(top: 70, left: 100, bottom: 70, right: 100)
)
view.addSubview(bookPreviewViewBackground)
Expand Down Expand Up @@ -138,6 +176,100 @@ final class BookCreationViewController: UIViewController {
height: 63
)
}
private func configureNavigationBar() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

오 네비게이션 바 좋네용
정현님 걸로 쓰면 될 거 같습니다

// 네비바 설정
navigationController?.navigationBar.isHidden = false

// 타이틀 설정
navigationController?.navigationBar.titleTextAttributes = [
.font: UIFont.ownglyphBerry(size: 17)
]
title = "책 표지 만들기"

// 왼쪽 버튼
let leftBarButtonAction = UIAction { [weak self] _ in
self?.navigationController?.popViewController(animated: true)
}
let leftBarButton = UIBarButtonItem(title: "닫기", primaryAction: leftBarButtonAction)
leftBarButton.setTitleTextAttributes([
.font: UIFont.ownglyphBerry(size: 17),
.foregroundColor: UIColor.mhTitle
], for: .normal)
navigationItem.leftBarButtonItem = leftBarButton

// 오른쪽 버튼
let rightBarButtonAction = UIAction { [weak self] _ in
// TODO: - 구현 해야 함
self?.navigationController?.popViewController(animated: true)
}
let rightBarButton = UIBarButtonItem(title: "책 속지 만들기", primaryAction: rightBarButtonAction)
rightBarButton.setTitleTextAttributes([
.font: UIFont.ownglyphBerry(size: 17),
.foregroundColor: UIColor.mhTitle
], for: .normal)
navigationItem.rightBarButtonItem = rightBarButton
}
private func configureAction() {
// 색깔 버튼
bookColorButtons.enumerated().forEach { idx, button in
let action = UIAction { [weak self] _ in
guard let self else { return }
self.viewModel.previousColorNumber = self.viewModel.currentColorNumber
self.viewModel.currentColorNumber = idx
}
button.addAction(action, for: .touchUpInside)
}

// TitleTextField 변경
let titleAction = UIAction { [weak self] _ in
guard let self else { return }
if self.bookTitleTextField.text?.count ?? 0 > Self.maxTitleLength {
self.bookTitleTextField.text = String(self.bookTitleTextField.text?.prefix(Self.maxTitleLength) ?? "")
}

self.viewModel.bookTitle = self.bookTitleTextField.text ?? ""
}
bookTitleTextField.addAction(titleAction, for: .editingChanged)

// TODO: - 카테고리 선택 뷰모델에 반영

// 사진선택 버튼
let pictureSelectingAction = UIAction { [weak self] _ in
let albumViewModel = CustomAlbumViewModel()
let customAlbumViewController = CustomAlbumViewController(viewModel: albumViewModel)
self?.navigationController?.pushViewController(customAlbumViewController, animated: true)
}
imageSelectionButton.addAction(pictureSelectingAction, for: .touchUpInside)

// TODO: - 사진 선택 뷰모델?에 반영

}
private func configureViewModelBinding() {
$viewModel
.receive(on: DispatchQueue.main)
.sink { [weak self] viewModel in
guard let self else { return }
self.bookView.configure(
title: viewModel.bookTitle,
bookCoverImage: viewModel.currentColor.image,
// TODO: - 이미지 선택시 변경
targetImage: .rotate,
houseName: viewModel.houseName
)
}
.store(in: &cancellables)
$viewModel
.receive(on: DispatchQueue.main)
.sink { [weak self] viewModel in
guard viewModel.previousColorNumber != -1 else { return }
guard let self else { return }
let previousButton = self.bookColorButtons[viewModel.previousColorNumber]
self.removeSubLayersAndaddOuterShadow(to: previousButton)
let currentColorButton = self.bookColorButtons[viewModel.currentColorNumber]
self.addInnerShadow(to: currentColorButton)
}
.store(in: &cancellables)
}
private func configuredColorButtons() -> UIView { // 린트 경고 때문에 분리
let firstLineColorButtonStackView = UIStackView()
firstLineColorButtonStackView.axis = .horizontal
Expand Down Expand Up @@ -166,4 +298,31 @@ final class BookCreationViewController: UIViewController {

return bookColorSelectionBackground
}
private func removeSubLayersAndaddOuterShadow(to view: UIView) {
UIView.animate(withDuration: 0.3) { [weak self] in
self?.colorButtonInnerShadow.removeFromSuperlayer()
Copy link
Collaborator

Choose a reason for hiding this comment

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

이게 그 inner shadow 문제의 코드인가용 ㅋㅋㅋㅋㅋ

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ㅠㅠ 디버깅이 친절하지 않아서 혼났네요...

view.layer.shadowOpacity = 0.25
}
}
private func addInnerShadow(to view: UIView) {
UIView.animate(withDuration: 0.3) { [weak self] in
guard let self else { return }
let bounds = view.bounds
let path = UIBezierPath(rect: bounds)
let cutoutPath = UIBezierPath(rect: bounds.insetBy(dx: 0, dy: -4)).reversing()
path.append(cutoutPath)

self.colorButtonInnerShadow.shadowPath = path.cgPath
self.colorButtonInnerShadow.frame = bounds
view.layer.shadowOpacity = 0
view.layer.addSublayer(self.colorButtonInnerShadow)
}
}
}

extension BookCreationViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import MHDomain
import MHFoundation
import Photos

struct BookCreationViewModel {
Copy link
Collaborator

Choose a reason for hiding this comment

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

P2: ViewModel을 struct로 만들어주셨는데 다른 곳들과 다르게 하신 이유가 있으신가요?? 뭔가 제가 느끼기에 해당 구조체는 MVVM의 ViewModel이라기보다는 BookCreation이라는 하나의 view에서 사용되는 model같다는 생각이 듭니다 !

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

일단, 만들어진 viewmodel이 영현님 자료밖에 없기도 했고, 제가 (input - output 구조 라고 할까요?)여기에 익숙하지 않았습니다. 또한 딱히 아직 viewmodel에 대해 제대로 정해진 바도 없기도 해서 그냥 당장 구현하는데에 필요할 정도로만 했습니다. 또한 자료형 밖에 없는 게 아직 usecase, entity도 코드상으로 정해지지 않기도 해서 입니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

결론 == 일단 구현하자 느낌으로 막 만듦

var bookTitle: String = ""
var bookCategory: String = ""
var previousColorNumber: Int = -1
var currentColorNumber: Int = 0
var coverPicture: PHAsset?
var currentColor: BookColor {
switch currentColorNumber {
case 0: .pink
case 1: .green
case 2: .blue
case 3: .orange
case 4: .beige
default: .blue
}
}
let houseName: String = UserDefaults.standard.string(forKey: Constant.houseNameUserDefaultKey) ?? ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import MHDomain
final class MHBookCover: UIView {
// MARK: - Property
private let bookCoverImageView = UIImageView()
private let titleLabel = UILabel(style: .default)
private let titleLabel: UILabel = {
let label = UILabel(style: .default)
label.adjustsFontSizeToFitWidth = true

return label
}()
private let targetImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
Expand Down Expand Up @@ -63,7 +68,8 @@ final class MHBookCover: UIView {
private func configureConstraints() {
bookCoverImageView.fillSuperview()
titleLabel.setTop(anchor: topAnchor, constant: 16)
titleLabel.setCenterX(view: self, constant: 8)
titleLabel.setLeading(anchor: leadingAnchor, constant: 25)
titleLabel.setTrailing(anchor: trailingAnchor, constant: 12)
targetImageView.setTop(anchor: titleLabel.bottomAnchor, constant: 14)
targetImageView.setCenterX(view: self, constant: 8)
targetImageView.setWidthAndHeight(width: 100, height: 110)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UIKit
import MHDomain
import MHFoundation

public final class HomeViewController: UIViewController {
// MARK: - Properties
Expand Down Expand Up @@ -39,7 +40,7 @@
}

required init?(coder: NSCoder) {
guard let houseName = UserDefaults.standard.string(forKey: "houseName") else { return nil }
guard let houseName = UserDefaults.standard.string(forKey: Constant.houseNameUserDefaultKey) else { return nil }
self.viewModel = HomeViewModel(houseName: houseName)
self.navigationBar = MHNavigationBar(title: viewModel.houseName)
super.init(coder: coder)
Expand Down Expand Up @@ -70,7 +71,7 @@
BookCollectionViewCell.self,
forCellWithReuseIdentifier: BookCollectionViewCell.identifier
)
currentCategoryLabel.text = "전체" // TODO: 카테고리 관리 필요

Check warning on line 74 in MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Todo Violation: TODOs should be resolved (카테고리 관리 필요) (todo)
categorySelectButton.setImage(.dropDown, for: .normal)
}

Expand All @@ -84,12 +85,12 @@

private func configureAction() {
categorySelectButton.addAction(UIAction { _ in
// TODO: 카테고리 시트지 띄우기

Check warning on line 88 in MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Todo Violation: TODOs should be resolved (카테고리 시트지 띄우기) (todo)
}, for: .touchUpInside)

makingBookFloatingButton.addAction(UIAction { [weak self] _ in
guard let self else { return }
let bookCreationViewController = BookCreationViewController()
let bookCreationViewController = BookCreationViewController(viewModel: BookCreationViewModel())
self.navigationController?.pushViewController(bookCreationViewController, animated: true)
}, for: .touchUpInside)
}
Expand Down Expand Up @@ -128,7 +129,7 @@
_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath
) {
// TODO: 책 펼치기 로직

Check warning on line 132 in MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Todo Violation: TODOs should be resolved (책 펼치기 로직) (todo)
}
}

Expand All @@ -149,7 +150,7 @@
withReuseIdentifier: BookCollectionViewCell.identifier,
for: indexPath
) as? BookCollectionViewCell else { return UICollectionViewCell() }
// TODO: 데이터 넣기

Check warning on line 153 in MemorialHouse/MHPresentation/MHPresentation/Source/Home/HomeViewController.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Todo Violation: TODOs should be resolved (데이터 넣기) (todo)

return cell
}
Expand Down
Loading