diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift index 5ff2648a..4304c2bb 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift @@ -55,7 +55,8 @@ struct DataDependencyAssembler: DependencyAssembler { DIContainer.shared.register(type: CommonQuestInterface.self) { _ in return DefaultCommonQuestRepository( network: networkService, - keychainService: keychainService + keychainService: keychainService, + userDefaultService: userDefaultService ) } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/Model/CommonQuestAnswersResponseDTO.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/Model/CommonQuestAnswersResponseDTO.swift index d0474117..8c3e1aae 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Data/Model/CommonQuestAnswersResponseDTO.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Data/Model/CommonQuestAnswersResponseDTO.swift @@ -25,7 +25,7 @@ struct CommonQuestAnswerResponseDTO: Decodable { } extension CommonQuestAnswersResponseDTO { - func toEntity() -> CommonQuestAnswersEntity { + func toEntity(userName: String) -> CommonQuestAnswersEntity { .init( question: question, questID: questId, @@ -33,14 +33,15 @@ extension CommonQuestAnswersResponseDTO { isAnswered: isAnswered, hasNext: hasNext, nextCursor: nil, - answers: answers.map { $0.toEntity() } + answers: answers.map { $0.toEntity(userName: userName) } ) } } extension CommonQuestAnswerResponseDTO { - func toEntity() -> CommonQuestAnswerEntity { + func toEntity(userName: String) -> CommonQuestAnswerEntity { .init( + isMyAnswer: userName == writer ? true : false, answerID: answerId, writer: writer, profileIcon: profileIcon, diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/CommonQuestRepository.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/CommonQuestRepository.swift index a4769162..c74198ca 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/CommonQuestRepository.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/CommonQuestRepository.swift @@ -11,13 +11,16 @@ struct DefaultCommonQuestRepository: CommonQuestInterface { private let network: NetworkService private let keychainService: KeychainService + private let userDefaultsService: UserDefaultService init( network: NetworkService, - keychainService: KeychainService + keychainService: KeychainService, + userDefaultService: UserDefaultService ) { self.network = network self.keychainService = keychainService + self.userDefaultsService = userDefaultService } func saveCommonQuest(questID: Int, answer: String) async throws { @@ -35,6 +38,7 @@ struct DefaultCommonQuestRepository: CommonQuestInterface { date: String, cursor: Int? ) async throws -> CommonQuestAnswersEntity { + let userName: String = userDefaultsService.load(key: .userName) ?? "" let commonQuest = try await network.request( CommonQuestAPI.fetchCommonQuest( date: date, @@ -42,7 +46,7 @@ struct DefaultCommonQuestRepository: CommonQuestInterface { ), decodingType: CommonQuestAnswersResponseDTO.self ) - return commonQuest.toEntity() + return commonQuest.toEntity(userName: userName) } func updateCommonQuest(answerID: Int, answer: String) async throws { diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/CommonQuestAnswersEntity.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/CommonQuestAnswersEntity.swift index 1d86ebdb..8edb6a71 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/CommonQuestAnswersEntity.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/CommonQuestAnswersEntity.swift @@ -18,6 +18,7 @@ struct CommonQuestAnswersEntity { } struct CommonQuestAnswerEntity { + let isMyAnswer: Bool let answerID: Int let writer: String let profileIcon: String @@ -32,6 +33,7 @@ extension CommonQuestAnswersEntity { static let allAnswers: [CommonQuestAnswerEntity] = (1...30).map { CommonQuestAnswerEntity( + isMyAnswer: false, answerID: $0, writer: "유저\($0)", profileIcon: profileIcons[$0 % 4], @@ -57,6 +59,7 @@ extension CommonQuestAnswersEntity { extension CommonQuestAnswerEntity { static func stub() -> Self { .init( + isMyAnswer: false, answerID: 1, writer: "장원영", profileIcon: "SO_SO", diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Modal/ConfirmModalView.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Modal/ConfirmModalView.swift index 7d4e81fb..4dc97516 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Modal/ConfirmModalView.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Modal/ConfirmModalView.swift @@ -12,6 +12,7 @@ enum ConfirmModalType { case withdraw case block case delete + case saveQuest var title: String { switch self { @@ -23,6 +24,8 @@ enum ConfirmModalType { "차단을 해제하시겠어요?" case .delete: "정말 삭제하시겠어요?" + case .saveQuest: + "작성을 완료하시겠어요?" } } @@ -34,6 +37,8 @@ enum ConfirmModalType { "탈퇴 시 모든 데이터가 삭제됩니다." case .delete: "삭제한 답변은 다시 복구할 수 없습니다." + case .saveQuest: + "완료하면 다른 사용자에게 공개돼요." } } } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Navigation/ByeBooNavigationBar.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Navigation/ByeBooNavigationBar.swift index a42d1334..461056c3 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Navigation/ByeBooNavigationBar.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/Navigation/ByeBooNavigationBar.swift @@ -17,6 +17,7 @@ enum NavigationHeaderType { enum NavigationBarType: Equatable { case back(header: NavigationHeaderType = .clear) case backAndMenu(header: NavigationHeaderType = .clear) + case backAndEdit(header: NavigationHeaderType = .clear) case title(String, header: NavigationHeaderType = .clear) case close(header: NavigationHeaderType = .clear) case titleAndClose(String, header: NavigationHeaderType = .clear) @@ -74,6 +75,7 @@ struct ByeBooNavigationBar { switch barType { case .back(let header), .backAndMenu(let header), + .backAndEdit(let header), .close(let header), .none(let header), .title(_, let header), @@ -143,6 +145,20 @@ struct ByeBooNavigationBar { navigationItem: navigationItem, action: secondAction ) + case .backAndEdit: + let backButtonItem = makeBarButtonItem( + image: .left.withTintColor(.white), + target: topViewController, + action: action + ) + navigationItem.leftBarButtonItem = backButtonItem + + let editButtonItem = makeBarButtonItem( + image: .edit, + target: topViewController, + action: secondAction + ) + navigationItem.rightBarButtonItem = editButtonItem case .title(let string, _): navigationItem.title = string diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/TextView/TextBoxView.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/TextView/TextBoxView.swift index bdf77807..2c45636d 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/TextView/TextBoxView.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Common/TextView/TextBoxView.swift @@ -40,8 +40,8 @@ final class TextBoxView: BaseView { backgroundColor = .white5 titleLabel.applyByeBooFont( - style: .body6R14, - color: .grayscale300, + style: .body3R16, + color: .grayscale100, numberOfLines: 0 ) titleLabel.lineBreakMode = .byCharWrapping @@ -75,9 +75,9 @@ final class TextBoxView: BaseView { extension TextBoxView { func updateText(_ text: String) { titleLabel.applyByeBooFont( - style: .body6R14, + style: .body3R16, text: text, - color: .grayscale300, + color: .grayscale100, numberOfLines: 0 ) } @@ -86,7 +86,7 @@ extension TextBoxView { titleLabel.applyByeBooFont( style: .body6R14, text: text, - color: .grayscale300, + color: .grayscale100, numberOfLines: 0 ) self.emotionChip?.updateEmotion(ByeBooEmotion.toEmotion(text: emotionState)) diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/View/BlockedUserListView.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/View/BlockedUserListView.swift index 05ddc53b..b10ae136 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/View/BlockedUserListView.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/View/BlockedUserListView.swift @@ -10,6 +10,7 @@ import UIKit final class BlockedUserListView: BaseView { private(set) var userTableView = UITableView() + private let emptyLabel = UILabel() override func setStyle() { self.do { @@ -19,10 +20,18 @@ final class BlockedUserListView: BaseView { $0.backgroundColor = .grayscale900 $0.separatorStyle = .none } + emptyLabel.do { + $0.applyByeBooFont( + style: .body6R14, + text: "차단하신 사용자가 없어요", + color: .grayscale400 + ) + $0.isHidden = true + } } override func setUI() { - addSubview(userTableView) + addSubviews(userTableView, emptyLabel) } override func setLayout() { @@ -31,5 +40,15 @@ final class BlockedUserListView: BaseView { $0.horizontalEdges.equalToSuperview() $0.bottom.equalToSuperview().inset(24.adjustedH) } + emptyLabel.snp.makeConstraints { + $0.top.equalToSuperview().inset(334.5.adjustedH) + $0.centerX.equalToSuperview() + } + } +} + +extension BlockedUserListView { + func updateEmptyLabel() { + self.emptyLabel.isHidden = false } } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/BlockedkUserListViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/BlockedkUserListViewController.swift index a50e82b7..e0eb8b2e 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/BlockedkUserListViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/BlockedkUserListViewController.swift @@ -62,6 +62,9 @@ extension BlockedkUserListViewController { switch result { case .success(let blockedList): ByeBooLogger.debug("차단 사용자 조회 성공 \(blockedList)") + if blockedList.isEmpty { + self.rootView.updateEmptyLabel() + } self.rootView.userTableView.reloadData() case .failure(let error): ByeBooLogger.error(error) diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/MyPageViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/MyPageViewController.swift index 33730a2e..c0a4eb61 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/MyPageViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewController/MyPageViewController.swift @@ -364,7 +364,7 @@ extension MyPageViewController { self.viewModel.action(.withdrawActionButtonDidTap) Mixpanel.mainInstance().track(event: MyPageEvents.Name.withdrawConfirmClick) - case .block, .delete: + case .block, .delete, .saveQuest: break } } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/ImagePickerContainer.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/ImagePickerContainer.swift index 3bc33ff2..5251863c 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/ImagePickerContainer.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/ImagePickerContainer.swift @@ -50,7 +50,7 @@ final class ImagePickerContainer: BaseView { plusIcon.do { $0.image = .plus.withRenderingMode(.alwaysTemplate) $0.contentMode = .scaleAspectFit - $0.tintColor = .primary300 + $0.tintColor = .grayscale500 } } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/QuestTextField.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/QuestTextField.swift index 4a99ac06..7b5e00dc 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/QuestTextField.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/QuestTextField.swift @@ -12,33 +12,23 @@ import Then final class QuestTextField: BaseView { private(set) var textView = UITextView() - private var descriptionStackView: UIStackView? - private let errorIcon = UIImageView() - private let descriptionLabel = UILabel() - private(set) var textCountLabel = UILabel() - private var questType: QuestType + var isPlaceholderActive: Bool = true var count: Int = 0 private(set) var placeholder: String private(set) var limitCount: Int private var containerHeightConsraint: Constraint? private var textViewHeightConstraint: Constraint? + private var lastTextViewHeight = 196.adjustedH - weak var delegate: QuestCompleteProtocol? + weak var questCompleteDelegate: QuestCompleteProtocol? + weak var questTextViewDelegate: WriteQuestTextViewProtocol? init(type: QuestType) { self.questType = type placeholder = type.plaeholder limitCount = type.textLimit - - switch type { - case .question: - descriptionStackView = UIStackView() - case .activation: - descriptionStackView = nil - } - super.init(frame: .zero) textView.delegate = self } @@ -48,12 +38,7 @@ final class QuestTextField: BaseView { } override func setUI() { - addSubviews(textView, textCountLabel) - - if let descriptionStackView { - addSubviews(descriptionStackView) - descriptionStackView.addArrangedSubviews(errorIcon, descriptionLabel) - } + addSubviews(textView) } override func setStyle() { @@ -71,37 +56,12 @@ final class QuestTextField: BaseView { color: .grayscale300 ) } - - textCountLabel.applyByeBooFont ( - style: .cap2R12, - text: "(\(count)/\(limitCount))", - color: .grayscale400 - ) - - if let descriptionStackView { - descriptionStackView.do { - $0.axis = .horizontal - $0.spacing = 3.adjustedW - } - } - - errorIcon.do { - $0.image = .error - $0.contentMode = .scaleAspectFit - } - - descriptionLabel.applyByeBooFont( - style: .cap2R12, - text: "10글자 이상 작성해 주세요.", - color: .grayscale400, - textAlignment: .center - ) } override func setLayout() { self.snp.makeConstraints { $0.width.equalTo(327.adjustedW) - containerHeightConsraint = $0.height.equalTo(268.adjustedH).constraint + containerHeightConsraint = $0.height.greaterThanOrEqualTo(268.adjustedH).constraint } textView.snp.makeConstraints { @@ -110,18 +70,6 @@ final class QuestTextField: BaseView { $0.bottom.equalToSuperview().inset(72.adjustedH) textViewHeightConstraint = $0.height.equalTo(196.adjustedH).constraint } - - if let descriptionStackView { - descriptionStackView.snp.makeConstraints { - $0.leading.equalToSuperview() - $0.bottom.equalToSuperview().inset(24.adjustedW) - } - } - - textCountLabel.snp.makeConstraints { - $0.trailing.equalToSuperview() - $0.bottom.equalToSuperview().inset(24.adjustedW) - } } } @@ -141,18 +89,15 @@ extension QuestTextField: UITextViewDelegate { } else { applyTextViewStyle(text: textView.text, color: .grayscale100) } - textCountLabel.textColor = .grayscale300 - updateTextViewHeight() + questTextViewDelegate?.textViewDidEndEditing() } func textViewDidChange(_ textView: UITextView) { if textView.text.count > limitCount { textView.deleteBackward() } - count = textView.text.count - textCountLabel.text = "(\(count)/\(limitCount))" - updateTextViewHeight() - delegate?.updateButtonWhenWriting(text: textView.text) + questCompleteDelegate?.updateButtonWhenWriting(text: textView.text) + questTextViewDelegate?.textViewDidChange(count: textView.text.count) } } @@ -165,16 +110,25 @@ extension QuestTextField { ) } - func updateTextViewHeight() { + func updateTextViewHeight() -> CGFloat { let width = self.frame.width let fittingSize = CGSize(width: width, height: .greatestFiniteMagnitude) let estimatedHeight = ceil(textView.sizeThatFits(fittingSize).height) let containerMinHeight = 268.adjustedH let textViewMinHeight = 196.adjustedH + let newHeight = max(textViewMinHeight, estimatedHeight) + let diff = newHeight - lastTextViewHeight + containerHeightConsraint?.update(offset: max(containerMinHeight, estimatedHeight + 72.adjustedH)) textViewHeightConstraint?.update(offset: max(textViewMinHeight, estimatedHeight)) - superview?.layoutIfNeeded() - layoutIfNeeded() + UIView.performWithoutAnimation { + self.superview?.layoutIfNeeded() + self.layoutIfNeeded() + } + + lastTextViewHeight = newHeight + + return diff } } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/ActivationType/WriteActiveTypeQuestView.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/ActivationType/WriteActiveTypeQuestView.swift index 2b87da9f..1981f37a 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/ActivationType/WriteActiveTypeQuestView.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/ActivationType/WriteActiveTypeQuestView.swift @@ -11,9 +11,12 @@ import SnapKit import Then final class WriteActiveTypeQuestView: BaseView { + private(set) var limitCount: Int = QuestType.activation.textLimit + var count: Int = 0 + private(set) var scrollView = UIScrollView() private let contentView = UIView() - + private(set) var headerView = WriteQuestTitleView(questNum: 0, title: "") private let divider = UIView() @@ -24,11 +27,15 @@ final class WriteActiveTypeQuestView: BaseView { var imgCount: Int = 0 private(set) var imageContainer = ImagePickerContainer() - private let textStackView = UIStackView() + private let questFieldTitleView = UIView() private let grayTag = ByeBooFilledTag(tagType: .smallGray, text: "선택") private let thinkTitleLabel = UILabel() private(set) var questTextField = QuestTextField(type: .activation) - + + private let bottomContainerView = UIView() + private(set) var textCountLabel = UILabel() + private var bottomConstraint: Constraint? + private var contentViewBottomConstraint: Constraint? override func setUI() { addSubviews(scrollView) @@ -38,18 +45,21 @@ final class WriteActiveTypeQuestView: BaseView { headerView, divider, imgTitleContainerView, - textStackView, + questFieldTitleView, imageContainer, - questTextField + questTextField, + bottomContainerView ) imgTitleContainerView.addSubviews( yellowTag, imgTitleLabel, imgCountLabel ) - textStackView.addArrangedSubviews( + questFieldTitleView.addSubviews( grayTag, thinkTitleLabel ) + + bottomContainerView.addSubview(textCountLabel) } override func setStyle() { @@ -57,7 +67,6 @@ final class WriteActiveTypeQuestView: BaseView { scrollView.do { $0.isScrollEnabled = true - $0.keyboardDismissMode = .onDrag $0.backgroundColor = .clear $0.isUserInteractionEnabled = true } @@ -83,17 +92,19 @@ final class WriteActiveTypeQuestView: BaseView { color: .grayscale400 ) - textStackView.do { - $0.axis = .horizontal - $0.spacing = 8 - $0.alignment = .center - } - thinkTitleLabel.applyByeBooFont( style: .body2M16, text: "생각 적기", color: .grayscale50 - ) + ) + + bottomContainerView.backgroundColor = .grayscale900 + + textCountLabel.applyByeBooFont ( + style: .cap2R12, + text: "\(count)/\(limitCount)", + color: .grayscale400 + ) } override func setLayout() { @@ -104,8 +115,9 @@ final class WriteActiveTypeQuestView: BaseView { contentView.snp.makeConstraints { $0.edges.equalTo(scrollView.contentLayoutGuide) $0.width.equalTo(scrollView.frameLayoutGuide) - $0.bottom.equalTo(questTextField.snp.bottom).offset(12.adjustedH) - $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide) + $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide).priority(250) + contentViewBottomConstraint = + $0.bottom.equalTo(bottomContainerView.snp.bottom).offset(32.adjustedH).constraint } headerView.snp.makeConstraints { @@ -149,18 +161,40 @@ final class WriteActiveTypeQuestView: BaseView { $0.width.height.equalTo(327.adjustedW) } - textStackView.snp.makeConstraints { + questFieldTitleView.snp.makeConstraints { $0.top.equalTo(imageContainer.snp.bottom).offset(16.adjustedH) - $0.width.equalTo(327.adjustedW) $0.height.equalTo(24.adjustedH) - $0.leading.trailing.equalToSuperview().inset(24.adjustedW) + $0.leading.equalToSuperview().inset(24.adjustedW) + } + + grayTag.snp.makeConstraints { + $0.top.equalToSuperview() + $0.leading.equalToSuperview() + $0.centerY.equalToSuperview() + } + + thinkTitleLabel.snp.makeConstraints { + $0.top.equalToSuperview() + $0.leading.equalTo(grayTag.snp.trailing).offset(8.adjustedH) + $0.centerY.equalToSuperview() } questTextField.snp.makeConstraints { - $0.top.equalTo(textStackView.snp.bottom).offset(8.adjustedH) + $0.top.equalTo(questFieldTitleView.snp.bottom).offset(12.adjustedH) $0.leading.trailing.equalToSuperview().inset(24.adjustedW) $0.height.greaterThanOrEqualTo(280.adjustedH) } + + bottomContainerView.snp.makeConstraints { + $0.top.equalTo(questTextField.snp.bottom).offset(32.adjustedH) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(42.adjustedH) + } + + textCountLabel.snp.makeConstraints { + $0.bottom.equalToSuperview().inset(13.adjustedH) + $0.trailing.equalToSuperview().inset(24.adjustedW) + } } override func touchesBegan(_ touches: Set, with event: UIEvent?) { @@ -168,20 +202,23 @@ final class WriteActiveTypeQuestView: BaseView { } func updateImageCountLabel(count: Int) { - imgCountLabel.text = "(\(count)/1)" + imgCountLabel.text = "\(count)/1" } } extension WriteActiveTypeQuestView: WriteQuestBaseProtocol { - var questTextView: UITextView { - questTextField.textView + var questTextView: QuestTextField { + questTextField } - var questCountLabelView: UIView { - questTextField.textCountLabel + var questCountLabelView: UILabel { + textCountLabel } var tipTagView: UIView { headerView.tipTag ?? UIView() } + var bottomView: UIView { + bottomContainerView + } } extension WriteActiveTypeQuestView { @@ -197,3 +234,55 @@ extension WriteActiveTypeQuestView { ) } } + +extension WriteActiveTypeQuestView: UpdateUIWhenKeyboardProtocol { + func updateUIWhenKeyboardUp() { + bottomContainerView.removeFromSuperview() + addSubview(bottomContainerView) + bottomContainerView.snp.remakeConstraints { + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(42.adjustedH) + bottomConstraint = $0.bottom.equalToSuperview().constraint + } + + contentView.snp.remakeConstraints { + $0.edges.equalTo(scrollView.contentLayoutGuide) + $0.width.equalTo(scrollView.frameLayoutGuide) + $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide).priority(250) + } + questTextField.snp.remakeConstraints { + $0.top.equalTo(questFieldTitleView.snp.bottom).offset(12.adjustedH) + $0.leading.trailing.equalToSuperview().inset(24.adjustedW) + $0.height.greaterThanOrEqualTo(280.adjustedH) + $0.bottom.equalToSuperview().inset(17.adjustedH) + } + } + + func updateUIWhenKeyboardDown() { + bottomContainerView.removeFromSuperview() + contentView.addSubview(bottomContainerView) + questTextField.snp.remakeConstraints { + $0.top.equalTo(questFieldTitleView.snp.bottom).offset(12.adjustedH) + $0.leading.trailing.equalToSuperview().inset(24.adjustedW) + $0.height.greaterThanOrEqualTo(280.adjustedH) + } + + bottomContainerView.snp.remakeConstraints { + $0.top.equalTo(questTextField.snp.bottom).offset(32.adjustedH) + $0.leading.trailing.equalToSuperview() + $0.bottom.equalToSuperview().inset(24.adjustedH) + $0.height.equalTo(42.adjustedH) + } + + contentView.snp.remakeConstraints { + $0.edges.equalTo(scrollView.contentLayoutGuide) + $0.width.equalTo(scrollView.frameLayoutGuide) + $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide).priority(250) + } + } + + func updateBottomConstraint(_ offset: CGFloat) { + bottomConstraint?.update(offset: offset) + } +} + diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/QuestionType/WriteQuestionTypeQuestView.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/QuestionType/WriteQuestionTypeQuestView.swift index c3dff053..ed525120 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/QuestionType/WriteQuestionTypeQuestView.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/View/QuestionType/WriteQuestionTypeQuestView.swift @@ -12,11 +12,23 @@ import Then final class WriteQuestionTypeQuestView: BaseView { private let questScope: QuestScope + private(set) var limitCount: Int = QuestType.question.textLimit + var count: Int = 0 + private(set) var scrollView = UIScrollView() private let contentView = UIView() + private(set) var headerView = WriteQuestTitleView(questNum: 0, title: "") private let divider = UIView() private(set) var questTextField = QuestTextField(type: .question) + private var descriptionStackView = UIStackView() + private let descriptionLabel = UILabel() + private(set) var textCountLabel = UILabel() + private let errorIcon = UIImageView() + private let bottomContainerView = UIView() + + private var bottomConstraint: Constraint? + private var contentViewBottomConstraint: Constraint? init(questScope: QuestScope) { self.questScope = questScope @@ -28,13 +40,16 @@ final class WriteQuestionTypeQuestView: BaseView { } override func setUI() { - addSubview(scrollView) + addSubviews(scrollView) scrollView.addSubview(contentView) contentView.addSubviews( headerView, divider, - questTextField + questTextField, + bottomContainerView ) + bottomContainerView.addSubviews(descriptionStackView, textCountLabel) + descriptionStackView.addArrangedSubviews(errorIcon, descriptionLabel) } override func setStyle() { @@ -42,7 +57,6 @@ final class WriteQuestionTypeQuestView: BaseView { scrollView.do { $0.isScrollEnabled = true - $0.keyboardDismissMode = .onDrag $0.backgroundColor = .clear $0.isUserInteractionEnabled = true } @@ -55,6 +69,31 @@ final class WriteQuestionTypeQuestView: BaseView { divider.do { $0.backgroundColor = .grayscale800 } + + descriptionStackView.do { + $0.axis = .horizontal + $0.spacing = 3.adjustedW + } + + textCountLabel.applyByeBooFont ( + style: .cap2R12, + text: "\(count)/\(limitCount)", + color: .grayscale400 + ) + + errorIcon.do { + $0.image = .error + $0.contentMode = .scaleAspectFit + } + + descriptionLabel.applyByeBooFont( + style: .cap2R12, + text: "10글자 이상 작성해 주세요.", + color: .grayscale400, + textAlignment: .center + ) + + bottomContainerView.backgroundColor = .grayscale900 } override func touchesBegan(_ touches: Set, with event: UIEvent?) { @@ -69,8 +108,9 @@ final class WriteQuestionTypeQuestView: BaseView { contentView.snp.makeConstraints { $0.edges.equalTo(scrollView.contentLayoutGuide) $0.width.equalTo(scrollView.frameLayoutGuide) - $0.bottom.equalTo(questTextField.snp.bottom).offset(12.adjustedH) $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide).priority(250) + contentViewBottomConstraint = + $0.bottom.equalTo(bottomContainerView.snp.bottom).offset(32.adjustedH).constraint } headerView.snp.makeConstraints { @@ -89,19 +129,38 @@ final class WriteQuestionTypeQuestView: BaseView { $0.leading.trailing.equalToSuperview().inset(24.adjustedW) $0.height.greaterThanOrEqualTo(268.adjustedH) } + + bottomContainerView.snp.makeConstraints { + $0.top.equalTo(questTextField.snp.bottom).offset(32.adjustedH) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(56.adjustedH) + } + + descriptionStackView.snp.makeConstraints { + $0.bottom.equalToSuperview().inset(13.adjustedH) + $0.leading.equalToSuperview().inset(24.adjustedW) + } + + textCountLabel.snp.makeConstraints { + $0.bottom.equalToSuperview().inset(13.adjustedH) + $0.trailing.equalToSuperview().inset(24.adjustedW) + } } } extension WriteQuestionTypeQuestView: WriteQuestBaseProtocol { - var questTextView: UITextView { - questTextField.textView + var questTextView: QuestTextField { + questTextField } - var questCountLabelView: UIView { - questTextField.textCountLabel + var questCountLabelView: UILabel { + textCountLabel } var tipTagView: UIView { headerView.tipTag ?? UIView() } + var bottomView: UIView { + bottomContainerView + } } extension WriteQuestionTypeQuestView { @@ -117,3 +176,54 @@ extension WriteQuestionTypeQuestView { ) } } + +extension WriteQuestionTypeQuestView: UpdateUIWhenKeyboardProtocol { + func updateUIWhenKeyboardUp() { + bottomContainerView.removeFromSuperview() + addSubview(bottomContainerView) + bottomContainerView.snp.remakeConstraints { + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(42.adjustedH) + bottomConstraint = $0.bottom.equalToSuperview().constraint + } + contentView.snp.remakeConstraints { + $0.edges.equalTo(scrollView.contentLayoutGuide) + $0.width.equalTo(scrollView.frameLayoutGuide) + $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide).priority(250) + } + + questTextField.snp.remakeConstraints { + $0.top.equalTo(divider.snp.bottom).offset(8.adjustedH) + $0.leading.trailing.equalToSuperview().inset(24.adjustedW) + $0.height.greaterThanOrEqualTo(280.adjustedH) + $0.bottom.equalToSuperview().inset(17.adjustedH) + } + } + + func updateUIWhenKeyboardDown() { + bottomContainerView.removeFromSuperview() + contentView.addSubview(bottomContainerView) + + questTextField.snp.remakeConstraints { + $0.top.equalTo(divider.snp.bottom).offset(20.adjustedH) + $0.leading.trailing.equalToSuperview().inset(24.adjustedW) + $0.height.greaterThanOrEqualTo(280.adjustedH) + } + + bottomContainerView.snp.remakeConstraints { + $0.top.equalTo(questTextField.snp.bottom).offset(32.adjustedH) + $0.leading.trailing.equalToSuperview() + $0.bottom.equalToSuperview().inset(17.adjustedH) + $0.height.equalTo(42.adjustedH) + } + contentView.snp.remakeConstraints { + $0.edges.equalTo(scrollView.contentLayoutGuide) + $0.width.equalTo(scrollView.frameLayoutGuide) + $0.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide).priority(250) + } + } + + func updateBottomConstraint(_ offset: CGFloat) { + bottomConstraint?.update(offset: offset) + } +} diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/WriteQuestTitleView.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/WriteQuestTitleView.swift index c89429ef..2682a983 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/WriteQuestTitleView.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/Write/WriteQuestTitleView.swift @@ -53,7 +53,7 @@ final class WriteQuestTitleView: BaseView { titleLabel.do { $0.applyByeBooFont( - style: .head1M24, + style: .head2M22, color: .white, textAlignment: .center, numberOfLines: 0 @@ -101,7 +101,7 @@ final class WriteQuestTitleView: BaseView { extension WriteQuestTitleView { func bind(questScope: QuestScope?, questNum: Int, title: String) { - self.questNum = questNum + questNumLabel.text = "\(questNum)번째 퀘스트" self.titleLabel.text = title if let questScope { diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ArchiveQuestViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ArchiveQuestViewController.swift index 00f7a3e0..92426597 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ArchiveQuestViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ArchiveQuestViewController.swift @@ -57,7 +57,15 @@ final class ArchiveQuestViewController: BaseViewController { type: .close(header: .black), action: #selector(close) ) - case .mypage, .questMain, .edit: + case .questMain: + ByeBooNavigationBar.makeNavigationBar( + navigationItem: self.navigationItem, + navigationController: self.navigationController, + type: .backAndEdit(header: .clear), + action: #selector(close), + secondAction: #selector(editButtonDidTap) + ) + case .mypage, .edit: ByeBooNavigationBar.makeNavigationBar( navigationItem: self.navigationItem, navigationController: self.navigationController, @@ -162,7 +170,12 @@ extension ArchiveQuestViewController { var viewController: ( BaseViewController & EditQuestProtocol ) viewController = setNavigateViewController(type: rootView.type) viewController.questMode = .edit - viewController.getExistingQuest(questID: self.viewModel.questID ,questAnswer: entity.answer, image: entity.imageUrl, imageKey: entity.imageKey) + viewController.getExistingQuest( + questID: self.viewModel.questID , + questAnswer: entity.answer, + questNumber: entity.questNumber, + image: entity.imageUrl, + imageKey: entity.imageKey) viewController.tabBarController?.tabBar.isHidden = true self.navigationController?.pushViewController(viewController, animated: false) } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestHistoryViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestHistoryViewController.swift index 6269ee1f..ae397fd9 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestHistoryViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestHistoryViewController.swift @@ -21,6 +21,11 @@ final class CommonQuestHistoryViewController: BaseViewController { view = rootView } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.tabBarController?.tabBar.isHidden = true + } + override func viewDidLoad() { super.viewDidLoad() @@ -104,14 +109,17 @@ extension CommonQuestHistoryViewController { nickname: String? = nil, content: String, answerID: Int? = nil, - writerID: Int? = nil + writerID: Int? = nil, + isMyAnswer: Bool? = nil ) { self.answerID = answerID self.answer = content self.question = question self.writtenAt = writtenAt - commonQuestArchiveType = nickname == nil ? .mine : .other + if let isMyAnswer { + commonQuestArchiveType = isMyAnswer ? .mine : .other + } if let writerID { self.writerID = writerID diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestViewController.swift index 190b1a97..eb47f5f4 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/CommonQuestViewController.swift @@ -142,10 +142,11 @@ extension CommonQuestViewController: UITableViewDelegate { profileIcon: viewModel.getProfileIcon(at: answerIndex), nickname: answer.writer, content: answer.content, - writerID: answer.writerID + answerID: answer.answerID, + writerID: answer.writerID, + isMyAnswer: answer.isMyAnswer ) historyViewController.navigationItem.hidesBackButton = true - self.navigationController?.pushViewController( historyViewController, animated: false diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ParentQuestViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ParentQuestViewController.swift index 553c8325..bc43c80d 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ParentQuestViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/ParentQuestViewController.swift @@ -56,6 +56,19 @@ final class ParentQuestViewController: BaseViewController, ToastPres tabBar.select(index: index) } + func presentCompleteModal() { + let modal = ModalBuilder( + modalView: QuestCompleteModal(), + action: nil, + rootViewController: self + ) + modal.present() + + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + modal.dismiss() + } + } + @objc private func handleToast(_ notification: Notification) { guard let type = notification.userInfo?["type"] as? CommonQuestArchiveType.Action else { return } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteActiveTypeQuestViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteActiveTypeQuestViewController.swift index be162017..fd11e45f 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteActiveTypeQuestViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteActiveTypeQuestViewController.swift @@ -62,7 +62,8 @@ final class WriteActiveTypeQuestViewController: WriteQuestBaseViewController: @@ -23,7 +37,6 @@ class WriteQuestBaseViewController: private var currentKeyboardOffset: CGFloat = 0 private var previousTextViewHeight: CGFloat = 0 - init(rootView: RootView) { self.rootView = rootView super.init(nibName: nil, bundle: nil) @@ -97,21 +110,37 @@ class WriteQuestBaseViewController: @objc func confirmButtonDidTap() { } @objc - private func textViewMoveUp(_ notification: NSNotification) { - guard let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { - return + private func keyboardWillUp(_ notification: NSNotification) { + guard let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double, + let curveRaw = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt + else { return } + + keyboardFrameInWindow = frame + scrollCountLabelIfNeeded() + applyKeyboardInset() + + let curve = UIView.AnimationOptions(rawValue: curveRaw << 16) + let keyboardHeight = max(0, view.bounds.height - frame.origin.y) + + if let rootView = rootView as? UpdateUIWhenKeyboardProtocol { + if keyboardHeight > 0 { + rootView.updateUIWhenKeyboardUp() + rootView.updateBottomConstraint(-keyboardHeight) + } + else { + rootView.updateUIWhenKeyboardDown() + } + } - keyboardFrameInWindow = keyboardFrame.cgRectValue - isKeyboardUsed = true - - DispatchQueue.main.async { [weak self] in - self?.applyKeyboardInset() - self?.scrollCountLabelIfNeeded() + UIView.animate(withDuration: duration, delay: 0, options: curve) { + self.view.layoutIfNeeded() } } + @objc - private func textViewMoveDown(_ notification: NSNotification) { + private func keyboardWillDown(_ notification: NSNotification) { keyboardFrameInWindow = .zero currentKeyboardOffset = 0 UIView.animate(withDuration: 0.3) { @@ -127,14 +156,46 @@ class WriteQuestBaseViewController: } extension WriteQuestBaseViewController { - func scrollCountLabelIfNeeded() { - let targetFrameInWindow = rootView.questCountLabelView.convert(rootView.questCountLabelView.bounds, to: nil) - guard keyboardOverlap(for: targetFrameInWindow) > 0 else { return } + func applyTextViewGrowth() { + let diff = rootView.questTextView.updateTextViewHeight() - let targetRect = rootView.questCountLabelView.convert(rootView.questCountLabelView.bounds, to: rootView.scrollView) - .insetBy(dx: 0, dy: -24.adjustedH) + guard diff > 0.5 else { return } - rootView.scrollView.scrollRectToVisible(targetRect, animated: true) + var offset = rootView.scrollView.contentOffset + offset.y += diff + let bottomContainerHeight = rootView.bottomView.frame.height + let maxOffsetY = rootView.scrollView.contentSize.height + - rootView.scrollView.bounds.height + + rootView.scrollView.contentInset.bottom + + bottomContainerHeight + + offset.y = min(offset.y, max(0, maxOffsetY)) + rootView.scrollView.setContentOffset(offset, animated: false) + } + + private func scrollCountLabelIfNeeded() { + let targetFrameInWindow = rootView.questCountLabelView.convert(rootView.questCountLabelView.bounds, to: nil) + let overlap = keyboardOverlap(for: targetFrameInWindow) + guard overlap > 0 else { return } + + let targetFrameInScroll = rootView.questCountLabelView.convert( + rootView.questCountLabelView.bounds, + to: rootView.scrollView + ) + + let bottomContainerHeight = rootView.bottomView.frame.height + let labelBottom = targetFrameInScroll.maxY + let visibleHeight = rootView.scrollView.frame.height + let padding: CGFloat = 200.adjustedH + + let targetOffsetY = labelBottom - visibleHeight + bottomContainerHeight + padding + + guard targetOffsetY > rootView.scrollView.contentOffset.y else { return } + + rootView.scrollView.setContentOffset( + CGPoint(x: 0, y: targetOffsetY), + animated: true + ) } private func keyboardOverlap(for rectInWindow: CGRect) -> CGFloat { @@ -161,12 +222,12 @@ extension WriteQuestBaseViewController { private func registerKeyboardNotificationCenter() { NotificationCenter.default.addObserver( self, - selector: #selector(textViewMoveUp), + selector: #selector(keyboardWillUp), name: UIResponder.keyboardWillShowNotification, object: nil ) NotificationCenter.default.addObserver( self, - selector: #selector(textViewMoveDown), + selector: #selector(keyboardWillDown), name: UIResponder.keyboardWillHideNotification, object: nil ) } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteQuestionTypeQuestViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteQuestionTypeQuestViewController.swift index 14aa6ad7..dfd40b89 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteQuestionTypeQuestViewController.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/ViewController/WriteQuestionTypeQuestViewController.swift @@ -38,6 +38,11 @@ final class WriteQuestionTypeQuestViewController: WriteQuestBaseViewController + else { return } + + targetViewController.presentCompleteModal() } } } + + private func createModalView() -> ConfirmModalView { + let dismissButton: ByeBooButton? = ByeBooButton(titleText: "아니오", type: .outline) + let actionButton = ByeBooButton(titleText: "예", type: .enabled) + return ConfirmModalView( + modalType: .saveQuest, + dismissButton: dismissButton, + actionButton: actionButton + ) + } + + private func presentConfirmModal() { + let isEdit = questMode == .edit ? true : false + let modalView = createModalView() + let action: () -> Void = { self.saveQuest(isEdit: isEdit, isCommonQuest: true) } + + ModalBuilder( + modalView: modalView, + action: action, + rootViewController: self + ).present() + } } extension WriteQuestionTypeQuestViewController: EditQuestProtocol { func getExistingQuest( questID: Int, questAnswer: String?, + questNumber: Int?, image: String?, imageKey: String? ) { self.questID = questID self.viewModel.action(.viewDidLoadWhenEditMode(questID: questID)) - guard let questAnswer = questAnswer else { + guard let questAnswer = questAnswer, let questNumber = questNumber else { return } self.answerText = questAnswer + self.questNumber = questNumber + setQuestTextField(answer: questAnswer) + rootView.textCountLabel.text = "\(answerText.count)/\(rootView.limitCount)" self.navigationItem.rightBarButtonItem?.isEnabled = false } } @@ -359,8 +388,18 @@ extension WriteQuestionTypeQuestViewController: EditQuestProtocol { extension WriteQuestionTypeQuestViewController: QuestCompleteProtocol { func updateButtonWhenWriting(text: String) { viewModel.action(.textFieldEditing(answerText: self.answerText, text: text)) - if isKeyboardUsed { - scrollCountLabelIfNeeded() - } + } +} + + +extension WriteQuestionTypeQuestViewController: WriteQuestTextViewProtocol { + func textViewDidEndEditing() { + self.rootView.questCountLabelView.textColor = .grayscale300 + self.rootView.updateUIWhenKeyboardDown() + } + + func textViewDidChange(count: Int) { + self.rootView.questCountLabelView.text = "\(count)/\(rootView.limitCount)" + applyTextViewGrowth() } } diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/EditQuestProtocol.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/EditQuestProtocol.swift index f50e4c5e..544217bd 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/EditQuestProtocol.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/EditQuestProtocol.swift @@ -7,5 +7,5 @@ protocol EditQuestProtocol { var questMode: QuestMode { get set } - func getExistingQuest(questID: Int, questAnswer: String?, image: String?, imageKey: String?) + func getExistingQuest(questID: Int, questAnswer: String?, questNumber: Int?, image: String?, imageKey: String?) }