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

EditPage에서 이미지 추가하는 기능 구현 #129

Merged
merged 1 commit into from
Dec 3, 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
Expand Up @@ -235,6 +235,7 @@ final class CustomAlbumViewController: UIViewController {
case .editPage:
editPhotoViewController = EditPhotoViewController(
mode: .editPage,
creationDate: creationDate,
completionHandler: completionHandler
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UIKit
import MHFoundation
import MHCore
import UIKit
import Combine

// TODO: - 페이지 없애는 기능 추가
Expand Down Expand Up @@ -216,9 +217,21 @@ final class EditBookViewController: UIViewController {
}
private func configureButtonAction() {
let addImageAction = UIAction { [weak self] _ in
// TODO: - 이미지 받는 임시 로직
guard let data = UIImage(resource: .bookMake).pngData() else { return }
self?.input.send(.didAddMediaWithData(type: .image, data: data))
let albumViewModel = CustomAlbumViewModel()
let customAlbumViewController = CustomAlbumViewController(
viewModel: albumViewModel,
mediaType: .image,
mode: .editPage
) { imageData, creationDate, caption in
let attributes: [String: any Sendable] = [
Constant.photoCreationDate: creationDate?.toString(),
Constant.photoCaption: caption
]
self?.input.send(.didAddMediaWithData(type: .image, attributes: attributes, data: imageData))
}
let navigationViewController = UINavigationController(rootViewController: customAlbumViewController)
Comment on lines +220 to +231
Copy link
Collaborator

Choose a reason for hiding this comment

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

미리 설정해줘야할 게 있으면 226~229번줄 처럼 attributes를 넣는 거군요,
동영상은 암것도 없어도 되겠죵..?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵넵 mediaType.video로 설정해주면 됩니당 .ᐟ.ᐟ 나머지는 default값을 넣어놔서 괜찮아용 !

navigationViewController.modalPresentationStyle = .fullScreen
self?.present(navigationViewController, animated: true)
}
addImageButton.addAction(addImageAction, for: .touchUpInside)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ final class EditPageCell: UITableViewCell {
configureAddSubView()
configureConstraints()
}

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

Expand Down Expand Up @@ -67,9 +68,11 @@ final class EditPageCell: UITableViewCell {
textStorage?.delegate = self
textView.delegate = self
}

private func configureAddSubView() {
contentView.addSubview(textView)
}

private func configureConstraints() {
textView.setAnchor(
top: contentView.topAnchor, constantTop: 10,
Expand All @@ -78,6 +81,7 @@ final class EditPageCell: UITableViewCell {
trailing: contentView.trailingAnchor, constantTrailing: 10
)
}

private func configureBinding() {
let output = viewModel?.transform(input: input.eraseToAnyPublisher())
output?
Expand Down Expand Up @@ -115,53 +119,111 @@ final class EditPageCell: UITableViewCell {
)
textStorage?.setAttributedString(mergedText)
}

/// Text와 Attachment 정보를 하나의 문자열로 조합합니다.
private func mergeStorageInformation(
text: String,
attachmentMetaData: [Int: MediaDescription]
) -> NSAttributedString {
let mutableAttributedString = NSMutableAttributedString(string: text)
attachmentMetaData.forEach { location, description in
// TODO: - MediaType 별로 바꿔줘야함
var mediaAttachment: MediaAttachment?
switch description.type {
case .image:
mediaAttachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: description
)
default:
break
}
input.send(.didRequestMediaDataForData(media: description))

guard let mediaAttachment else { return }
let range = NSRange(location: location, length: 1)
let mediaAttachment = MediaAttachment(
view: MHPolaroidPhotoView(), // TODO: - 이거 바꿔줘야함...
description: description
)
let attachmentString = NSAttributedString(attachment: mediaAttachment)
// Placeholder(공백) 교체
mutableAttributedString.replaceCharacters(in: range, with: attachmentString)
input.send(.didRequestMediaDataForData(media: description))
}

mutableAttributedString.addAttributes(defaultAttributes,
range: NSRange(location: 0, length: mutableAttributedString.length))
mutableAttributedString.addAttributes(
defaultAttributes,
range: NSRange(
location: 0,
length: mutableAttributedString.length
)
)

return mutableAttributedString
}

private func mediaAddedWithData(media: MediaDescription, data: Data) {
let attachment = MediaAttachment(
view: MHPolaroidPhotoView(), // TODO: - 수정 필요
description: media
)
var attachment: MediaAttachment?
switch media.type {
case .image:
attachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: media
)
case .video:
// TODO: - video 추가 필요
attachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: media
)
case .audio:
// TODO: - audio 추가 필요
attachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: media
)
default:
break
}
guard let attachment else { return }
attachment.configure(with: data)
appendAttachment(attachment)
}

private func mediaAddedWithURL(media: MediaDescription, url: URL) {
let attachment = MediaAttachment(
view: MHPolaroidPhotoView(),// TODO: - 수정 필요
description: media
)
var attachment: MediaAttachment?
switch media.type {
case .image:
attachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: media
)
case .video:
// TODO: - video 추가 필요
attachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: media
)
case .audio:
// TODO: - audio 추가 필요
attachment = MediaAttachment(
view: MHPolaroidPhotoView(),
description: media
)
default:
break
}
guard let attachment else { return }
attachment.configure(with: url)
appendAttachment(attachment)
}

private func mediaLoadedWithData(media: MediaDescription, data: Data) {
let attachment = findAttachment(by: media)
attachment?.configure(with: data)
}

private func mediaLoadedWithURL(media: MediaDescription, url: URL) {
let attachment = findAttachment(by: media)
attachment?.configure(with: url)
}

/// Text에서 특정 Attachment를 찾아서 적용합니다.
private func findAttachment(
by media: MediaDescription
Expand All @@ -179,6 +241,7 @@ final class EditPageCell: UITableViewCell {
}
return attachment
}

private func appendAttachment(_ attachment: MediaAttachment) {
guard let textStorage else { return }
let text = NSMutableAttributedString(attachment: attachment)
Expand Down Expand Up @@ -251,9 +314,11 @@ extension EditPageCell: UITextViewDelegate {
return text.isEmpty
|| isAcceptableHeight(textStorage, shouldChangeTextIn: range, replacementText: attributedText)
}

func textViewDidBeginEditing(_ textView: UITextView) {
input.send(.didBeginEditingPage)
}

/// TextView의 높이가 적절한지 확인합니다.
private func isAcceptableHeight(
_ textStorage: NSTextStorage,
Expand Down Expand Up @@ -289,6 +354,7 @@ extension EditPageCell: @preconcurrency NSTextStorageDelegate {
guard delta > 0 else { return }
lineBreakForAttachment()
}

func textStorage(
_ textStorage: NSTextStorage,
didProcessEditing editedMask: NSTextStorage.EditActions,
Expand All @@ -297,12 +363,14 @@ extension EditPageCell: @preconcurrency NSTextStorageDelegate {
) {
input.send(.didEditPage(attributedText: textStorage))
}

// 그곳에 Attachment가 있는지 확인합니다.
private func attachmentAt(_ index: Int) -> MediaAttachment? {
guard let textStorage else { return nil }
guard index >= 0 && index < textStorage.length else { return nil }
return textStorage.attributes(at: index, effectiveRange: nil)[.attachment] as? MediaAttachment
}

private func lineBreakForAttachment() {
guard let currentString = textStorage?.string else { return }
let startIndex = currentString.startIndex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ final class EditBookViewModel: ViewModelType {
// MARK: - Type
enum Input {
case viewDidLoad
case didAddMediaWithData(type: MediaType, data: Data)
case didAddMediaInURL(type: MediaType, url: URL)
case didAddMediaWithData(type: MediaType, attributes: [String: any Sendable]?, data: Data)
case didAddMediaInURL(type: MediaType, attributes: [String: any Sendable]?, url: URL)
case addPageButtonTapped
case didSaveButtonTapped
case didCancelButtonTapped
Expand Down Expand Up @@ -57,10 +57,10 @@ final class EditBookViewModel: ViewModelType {
switch event {
case .viewDidLoad:
Task { await self?.fetchBook() }
case let .didAddMediaWithData(type, data):
Task { await self?.addMedia(type: type, with: data) }
case let .didAddMediaInURL(type, url):
Task { await self?.addMedia(type: type, in: url) }
case let .didAddMediaWithData(type, attributes, data):
Task { await self?.addMedia(type: type, attributes: attributes, with: data) }
case let .didAddMediaInURL(type, attributes, url):
Task { await self?.addMedia(type: type, attributes: attributes, in: url) }
case .addPageButtonTapped:
self?.addEmptyPage()
case .didSaveButtonTapped:
Expand All @@ -72,6 +72,7 @@ final class EditBookViewModel: ViewModelType {

return output.eraseToAnyPublisher()
}

private func fetchBook() async {
do {
let book = try await fetchBookUseCase.execute(id: bookID)
Expand All @@ -92,11 +93,9 @@ final class EditBookViewModel: ViewModelType {
MHLogger.error(error.localizedDescription + #function)
}
}
private func addMedia(type: MediaType, with data: Data) async {
let description = MediaDescription(
id: UUID(),
type: type
)

private func addMedia(type: MediaType, attributes: [String: any Sendable]?, with data: Data) async {
let description = MediaDescription(type: type, attributes: attributes)
do {
try await createMediaUseCase.execute(media: description, data: data, at: bookID)
editPageViewModels[currentPageIndex].addMedia(media: description, data: data)
Expand All @@ -105,11 +104,9 @@ final class EditBookViewModel: ViewModelType {
MHLogger.error(error.localizedDescription + #function)
}
}
private func addMedia(type: MediaType, in url: URL) async {
let description = MediaDescription(
id: UUID(),
type: type
)

private func addMedia(type: MediaType, attributes: [String: any Sendable]?, in url: URL) async {
let description = MediaDescription(type: type, attributes: attributes)
do {
try await createMediaUseCase.execute(media: description, from: url, at: bookID)
editPageViewModels[currentPageIndex].addMedia(media: description, url: url)
Expand All @@ -118,18 +115,19 @@ final class EditBookViewModel: ViewModelType {
MHLogger.error(error.localizedDescription + #function)
}
}

private func addEmptyPage() {
let page = Page(id: UUID(), metadata: [:], text: "")
let editPageViewModel = EditPageViewModel(
fetchMediaUseCase: fetchMediaUseCase,
deleteMediaUseCase: deleteMediaUseCase,
bookID: bookID,
page: page
page: Page()
)
editPageViewModel.delegate = self
editPageViewModels.append(editPageViewModel)
output.send(.updateViewController(title: title))
}

private func saveMediaAll() async {
let pages = editPageViewModels.map { $0.page }
let book = Book(id: bookID, title: title, pages: pages)
Expand All @@ -142,6 +140,7 @@ final class EditBookViewModel: ViewModelType {
MHLogger.error(error.localizedDescription + #function)
}
}

private func revokeMediaAll() async {
do {
try await storeMediaUseCase.execute(to: bookID, mediaList: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,21 @@ final class EditPageViewModel: ViewModelType {

return output.eraseToAnyPublisher()
}

private func pageWillAppear() {
output.send(.page(page: page))
}

private func pageWillDisappear() {
cancellables.forEach { $0.cancel() }
cancellables = []
}

private func didEditPage(text: NSAttributedString) {
let page = converTextToPage(text: text)
self.page = page
}

private func loadMediaForData(media: MediaDescription) async {
do {
let mediaData: Data = try await fetchMediaUseCase.execute(media: media, in: bookID)
Expand All @@ -89,6 +93,7 @@ final class EditPageViewModel: ViewModelType {
MHLogger.error(error.localizedDescription + #function)
}
}

private func loadMediaForURL(media: MediaDescription) async {
do {
let mediaURL: URL = try await fetchMediaUseCase.execute(media: media, in: bookID)
Expand All @@ -103,9 +108,11 @@ final class EditPageViewModel: ViewModelType {
func addMedia(media: MediaDescription, data: Data) {
output.send(.mediaAddedWithData(media: media, data: data))
}

func addMedia(media: MediaDescription, url: URL) {
output.send(.mediaAddedWithURL(media: media, url: url))
}

func didBeginEditingPage() {
delegate?.didBeginEditingPage(self, page: page)
}
Expand All @@ -120,6 +127,7 @@ final class EditPageViewModel: ViewModelType {
)
return newPage
}

/// NSAttributedString에서 Text와 Attachment 정보를 추출해냅니다.
private func separateStorageInformation(
_ text: NSAttributedString
Expand Down
Loading