-
Notifications
You must be signed in to change notification settings - Fork 1
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
Changes from all commits
741c44a
2eb614a
df86361
445a5ba
c74ce35
abd14cd
74947f3
7febfa9
37709dd
6628481
92206c2
8972417
45280ed
3a87fd6
e519512
684cb48
b4a683a
1fd2c3e
b1131ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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) | ||
|
@@ -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() | ||
configureAction() | ||
} | ||
override func viewDidAppear(_ animated: Bool) { | ||
super.viewDidAppear(animated) | ||
let currentColorButton = bookColorButtons[viewModel.currentColorNumber] | ||
self.addInnerShadow(to: currentColorButton) | ||
} | ||
|
||
// MARK: - TouchEvent | ||
|
@@ -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) | ||
|
@@ -138,6 +176,100 @@ final class BookCreationViewController: UIViewController { | |
height: 63 | ||
) | ||
} | ||
private func configureNavigationBar() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
@@ -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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이게 그 inner shadow 문제의 코드인가용 ㅋㅋㅋㅋㅋ There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: ViewModel을 struct로 만들어주셨는데 다른 곳들과 다르게 하신 이유가 있으신가요?? 뭔가 제가 느끼기에 해당 구조체는 MVVM의 ViewModel이라기보다는 BookCreation이라는 하나의 view에서 사용되는 model같다는 생각이 듭니다 ! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일단, 만들어진 viewmodel이 영현님 자료밖에 없기도 했고, 제가 (input - output 구조 라고 할까요?)여기에 익숙하지 않았습니다. 또한 딱히 아직 viewmodel에 대해 제대로 정해진 바도 없기도 해서 그냥 당장 구현하는데에 필요할 정도로만 했습니다. 또한 자료형 밖에 없는 게 아직 usecase, entity도 코드상으로 정해지지 않기도 해서 입니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) ?? "" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: 바인딩을 viewDidLoad가 아닌 viewWillAppear에서 해주신 이유가 있으신가요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
화면에 안보이면 바인딩을 중지하기 위해서입니다!