From 958488f043a14bee2a22c7f11d8c54b5fa999369 Mon Sep 17 00:00:00 2001 From: Kyoungmi <1mmgm.dev@gmail.com> Date: Wed, 6 Dec 2023 20:49:03 +0900 Subject: [PATCH] [#166] refactor: answerViwModel data binding --- TellingMe/tellingMe.xcodeproj/project.pbxproj | 4 + .../tellingMe/data/answer/API/AnswerAPI.swift | 25 ++-- .../HeaderViewWithEmotionView.swift | 2 +- .../answer/view/AnswerBottomView.swift | 8 ++ .../answer/view/SelectEmotionView.swift | 28 ++++- .../AAnswerViewController.swift | 119 +++++++++++++++--- .../answer/viewModel/AnswerViewModel.swift | 96 +++++++++++--- .../common/answer/AnswerTextView.swift | 6 + .../common/emotion/EmotionView.swift | 5 + .../common/modal/MModalView.swift | 112 +++++++++++++++++ .../CommunicationListViewController.swift | 4 +- .../tellingMe/util/nameSpace/Emotions.swift | 16 +-- 12 files changed, 359 insertions(+), 66 deletions(-) create mode 100644 TellingMe/tellingMe/presentation/common/modal/MModalView.swift diff --git a/TellingMe/tellingMe.xcodeproj/project.pbxproj b/TellingMe/tellingMe.xcodeproj/project.pbxproj index b5f34ef0..5a2a9ff2 100644 --- a/TellingMe/tellingMe.xcodeproj/project.pbxproj +++ b/TellingMe/tellingMe.xcodeproj/project.pbxproj @@ -211,6 +211,7 @@ 3AEED26329C99F1500D02F3F /* HeadlineLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEED26229C99F1500D02F3F /* HeadlineLabel.swift */; }; 3AEED26529C99F7D00D02F3F /* BodyLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEED26429C99F7D00D02F3F /* BodyLabel.swift */; }; 3AEED26729C99F8800D02F3F /* CaptionLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEED26629C99F8800D02F3F /* CaptionLabel.swift */; }; + 3AF19F1B2B20783900AFAE70 /* MModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF19F1A2B20783900AFAE70 /* MModalView.swift */; }; 3AF324B02ABDE9A600995DBE /* OtherFeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF324AF2ABDE9A600995DBE /* OtherFeedbackView.swift */; }; 3AF324B32ABF5B8C00995DBE /* QuestionFeedbackDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF324B22ABF5B8C00995DBE /* QuestionFeedbackDTO.swift */; }; 3AF324B72ABF5BB200995DBE /* QuestionFeedbackAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF324B62ABF5BB200995DBE /* QuestionFeedbackAPI.swift */; }; @@ -561,6 +562,7 @@ 3AEED26229C99F1500D02F3F /* HeadlineLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineLabel.swift; sourceTree = ""; }; 3AEED26429C99F7D00D02F3F /* BodyLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BodyLabel.swift; sourceTree = ""; }; 3AEED26629C99F8800D02F3F /* CaptionLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptionLabel.swift; sourceTree = ""; }; + 3AF19F1A2B20783900AFAE70 /* MModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MModalView.swift; sourceTree = ""; }; 3AF324AF2ABDE9A600995DBE /* OtherFeedbackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherFeedbackView.swift; sourceTree = ""; }; 3AF324B22ABF5B8C00995DBE /* QuestionFeedbackDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionFeedbackDTO.swift; sourceTree = ""; }; 3AF324B62ABF5BB200995DBE /* QuestionFeedbackAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionFeedbackAPI.swift; sourceTree = ""; }; @@ -1819,6 +1821,7 @@ children = ( 3AFA371F2A1A5AB0008A5657 /* Modal.storyboard */, 3A1E403A2A1A611800F1F109 /* ModalViewController.swift */, + 3AF19F1A2B20783900AFAE70 /* MModalView.swift */, ); path = modal; sourceTree = ""; @@ -2516,6 +2519,7 @@ 3A9F319F2AF13BCA004B3416 /* SpecialQuestionView.swift in Sources */, 3A3739C92A13E4F900739543 /* SettingViewModel.swift in Sources */, 3A8FAACB2ACC297D008C8CA3 /* SignUpModel.swift in Sources */, + 3AF19F1B2B20783900AFAE70 /* MModalView.swift in Sources */, 58BB76EB2AD80AFA004AF4BE /* Products.swift in Sources */, 3A320F582A73E57E0098E8C9 /* CommunicationList.swift in Sources */, 3AC9D53829D58D8E006A2566 /* DropDownTableViewCell.swift in Sources */, diff --git a/TellingMe/tellingMe/data/answer/API/AnswerAPI.swift b/TellingMe/tellingMe/data/answer/API/AnswerAPI.swift index 2c1d4276..492fd929 100644 --- a/TellingMe/tellingMe/data/answer/API/AnswerAPI.swift +++ b/TellingMe/tellingMe/data/answer/API/AnswerAPI.swift @@ -134,22 +134,6 @@ struct AnswerAPI: Networkable { } } -// static func getAnswerWithId(query: Int) -> Observable { -// return Observable.create { observer in -// try makeAuthorizedProvider().requestO(.getAnswerWithId(query: query), dtoType: GetAnswerRespose.self) { result in -// switch result { -// case .success(let response): -// observer.onNext(response) -// observer.onCompleted() -// case .failure(let error): -// observer.onError(APIError.other(error)) -// } -// } -// -// return Disposables.create() -// } -// } - static func getAnswerWithId(query: Int) -> Observable { do { let provider = try makeAuthorizedProvider() @@ -182,6 +166,15 @@ struct AnswerAPI: Networkable { completion(.failure(APIError.other(error))) } } + + static func registerAnswer(request: RegisterAnswerRequest) -> Observable { + do { + let provider = try makeAuthorizedProvider() + return provider.request(target: .registerAnswer(request: request)) + } catch { + return Observable.error(error) + } + } static func getAnswerRecord(query: String, completion: @escaping(Result) -> Void) { do { diff --git a/TellingMe/tellingMe/presentation/alarm/views/DetailAnswer/HeaderViewWithEmotionView.swift b/TellingMe/tellingMe/presentation/alarm/views/DetailAnswer/HeaderViewWithEmotionView.swift index 37e6d9f6..d53b507c 100644 --- a/TellingMe/tellingMe/presentation/alarm/views/DetailAnswer/HeaderViewWithEmotionView.swift +++ b/TellingMe/tellingMe/presentation/alarm/views/DetailAnswer/HeaderViewWithEmotionView.swift @@ -127,7 +127,7 @@ extension HeaderViewWithEmotionView { extension HeaderViewWithEmotionView { func configure(data: AnswerForAlarmModel) { - guard let emotion = Emotions(intValue: data.emotion) else { return } + let emotion = Emotions(intValue: data.emotion) emotionImageView.image = UIImage(named: emotion.rawValue) emotionTitleLabel.text = emotion.stringValue questionTitleLabel.text = data.question diff --git a/TellingMe/tellingMe/presentation/answer/view/AnswerBottomView.swift b/TellingMe/tellingMe/presentation/answer/view/AnswerBottomView.swift index 401e1ed9..435c8c16 100644 --- a/TellingMe/tellingMe/presentation/answer/view/AnswerBottomView.swift +++ b/TellingMe/tellingMe/presentation/answer/view/AnswerBottomView.swift @@ -19,10 +19,18 @@ final class AnswerBottomView: BBaseView { private let publicSwitch = UISwitch() private let registerButton = UIButton() + var countTextObservable: Binder { + return countTextLabel.rx.text + } + var registerButtonTapObservable: Observable { return registerButton.rx.tap.asObservable() } + var togglePublicSwitch: ControlProperty { + return publicSwitch.rx.isOn + } + override init(frame: CGRect) { super.init(frame: frame) } diff --git a/TellingMe/tellingMe/presentation/answer/view/SelectEmotionView.swift b/TellingMe/tellingMe/presentation/answer/view/SelectEmotionView.swift index 66496e2c..71f2d9f0 100644 --- a/TellingMe/tellingMe/presentation/answer/view/SelectEmotionView.swift +++ b/TellingMe/tellingMe/presentation/answer/view/SelectEmotionView.swift @@ -20,11 +20,19 @@ final class SelectEmotionView: BBaseView { private let contentView = UIView() private let titleLabel = UILabel() private let emotionLabel = UILabel() - let emotionCollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + private let emotionCollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) private let buttonStackView = UIStackView() private let cancelButton = TeritaryTextButton() private let confirmButton = SecondaryTextButton() + var collectionViewRx: Reactive { + return emotionCollectionView.rx + } + + var confirmTapObservable: Observable { + return confirmButton.rx.tap.asObservable() + } + init(viewModel: AnswerViewModel, frame: CGRect) { self.viewModel = viewModel super.init(frame: frame) @@ -48,6 +56,13 @@ final class SelectEmotionView: BBaseView { self.selectEmotion(indexPath: indexPath) }) .disposed(by: disposeBag) + + Observable.just(viewModel.emotionList) + .bind(to: emotionCollectionView.rx.items(cellIdentifier: EmotionCollectionViewCell.id, cellType: EmotionCollectionViewCell.self)) { (row, emotion, cell) in + cell.setAlpha() + cell.setCell(with: emotion.rawValue) + } + .disposed(by: disposeBag) } override func setStyles() { @@ -55,6 +70,8 @@ final class SelectEmotionView: BBaseView { contentView.do { $0.backgroundColor = .Side100 + $0.layer.cornerRadius = 28 + $0.setTopCornerRadius() } titleLabel.do { @@ -69,6 +86,13 @@ final class SelectEmotionView: BBaseView { $0.text = AnswerStrings.emotionPlaceHolder.stringValue } + emotionCollectionView.rx.itemSelected + .bind(onNext: { [weak self] indexPath in + guard let self else { return } + self.viewModel.inputs.selectEmotion(indexPath: indexPath) + }) + .disposed(by: disposeBag) + emotionCollectionView.do { $0.backgroundColor = .Side100 $0.register(EmotionCollectionViewCell.self, forCellWithReuseIdentifier: EmotionCollectionViewCell.id) @@ -134,7 +158,7 @@ extension SelectEmotionView { if let cell = emotionCollectionView.cellForItem(at: indexPath) as? EmotionCollectionViewCell { cell.setOrigin() } - self.emotionLabel.text = viewModel.emotionList[indexPath.row].stringValue + self.emotionLabel.text = viewModel.emotionList[indexPath.row - 1].stringValue } } diff --git a/TellingMe/tellingMe/presentation/answer/viewController/AAnswerViewController.swift b/TellingMe/tellingMe/presentation/answer/viewController/AAnswerViewController.swift index 4fbafac7..5591c801 100644 --- a/TellingMe/tellingMe/presentation/answer/viewController/AAnswerViewController.swift +++ b/TellingMe/tellingMe/presentation/answer/viewController/AAnswerViewController.swift @@ -23,6 +23,7 @@ class AAnswerViewController: BaseViewController { private let answerBottomView = AnswerBottomView() private let emotionView = EmotionView() private let emotionSheetView: SelectEmotionView + private let backModal = MModalView() override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { emotionSheetView = SelectEmotionView(viewModel: viewModel, frame: .zero) @@ -38,46 +39,104 @@ class AAnswerViewController: BaseViewController { } + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + self.view.endEditing(true) + } + override func bindViewModel() { backHeaderView.backButtonTapObservable - .bind(onNext: { - self.navigationController?.popViewController(animated: true) + .bind(onNext: { [weak self] _ in + guard let self else { return } + showBackModal() }) .disposed(by: disposeBag) backHeaderView.rightButtonTapObservable - .bind(onNext: { + .bind(onNext: { [weak self] _ in + guard let self else { return } self.toggleQuestion() }) .disposed(by: disposeBag) - answerBottomView.registerButtonTapObservable - .bind(onNext: { - self.showEmotionSheetView() + backModal.leftButtonTapObservable + .subscribe(onNext: { [weak self] _ in + guard let self else { return } + backModal.isHidden = true + }) + .disposed(by: disposeBag) + + backModal.rightButtonTapObservable + .subscribe(onNext: { [weak self] _ in + guard let self else { return } + self.navigationController?.popViewController(animated: true) }) .disposed(by: disposeBag) - emotionSheetView.emotionCollectionView.rx.setDelegate(self) + answerBottomView.registerButtonTapObservable + .bind(to: viewModel.inputs.completeButtonTapped) .disposed(by: disposeBag) - emotionSheetView.emotionCollectionView.rx.itemSelected - .bind(onNext: { [weak self] indexPath in - guard let self = self else { return } - self.viewModel.inputs.selectEmotion(indexPath: indexPath) - }) + answerBottomView.togglePublicSwitch + .bind(to: viewModel.inputs.toggleSwitch) + .disposed(by: disposeBag) + + emotionSheetView.collectionViewRx.setDelegate(self) + .disposed(by: disposeBag) + + emotionSheetView.confirmTapObservable + .bind(to: viewModel.inputs.registerButtonTapped) + .disposed(by: disposeBag) + + answerTextView.textViewRxText + .orEmpty + .bind(to: viewModel.inputs.inputText) .disposed(by: disposeBag) viewModel.outputs.questionSubject - .bind(onNext: { question in + .bind(onNext: { [weak self] question in + guard let self else { return } self.questionView.setQuestion(data: question) }) .disposed(by: disposeBag) - Observable.just(viewModel.emotionList) - .bind(to: emotionSheetView.emotionCollectionView.rx.items(cellIdentifier: EmotionCollectionViewCell.id, cellType: EmotionCollectionViewCell.self)) { (row, emotion, cell) in - cell.setAlpha() - cell.setCell(with: emotion.rawValue) - } + viewModel.outputs.showEmotionSubject + .bind(onNext: { [weak self] _ in + guard let self else { return } + self.view.endEditing(true) + self.showEmotionSheetView() + }) + .disposed(by: disposeBag) + + viewModel.outputs.toastSubject + .bind(onNext: { [weak self] message in + guard let self else { return } + self.view.endEditing(true) + self.showToast(message: message) + }) + .disposed(by: disposeBag) + + viewModel.outputs.countTextRelay + .bind(to: answerBottomView.countTextObservable) + .disposed(by: disposeBag) + + viewModel.outputs.inputTextRelay + .bind(to: answerTextView.textViewRxText) + .disposed(by: disposeBag) + + viewModel.outputs.selectedEmotionIndexSubject + .bind(onNext: { [weak self] indexPath in + guard let self else { return } + self.emotionView.isHidden = false + self.emotionView.setEmotion(emotion: Emotions(intValue: indexPath.row + 1)) + }) + .disposed(by: disposeBag) + + viewModel.outputs.successRegisterSubject + .bind(onNext: { [weak self] _ in + guard let self else { return } + self.navigationController?.popViewController(animated: true) + }) .disposed(by: disposeBag) } @@ -86,6 +145,16 @@ class AAnswerViewController: BaseViewController { $0.setRightButton(image: UIImage(systemName: "chevron.down")!) } + backModal.do { + $0.isHidden = true + $0.setModalTitle(title: "작성을 취소하고 나가시겠어요?", subTitle: "작성한 답변은 초기화돼요") + $0.setModalButton(leftButtonTitle: "아니요", rightButtonTitle: "나갈래요") + } + + emotionView.do { + $0.isHidden = true + } + seperateLine.do { $0.backgroundColor = .Side300 } @@ -97,7 +166,8 @@ class AAnswerViewController: BaseViewController { override func setLayout() { view.addSubviews(backHeaderView, questionView, seperateLine, - answerTextView, answerBottomView, emotionSheetView) + answerTextView, answerBottomView, emotionSheetView, + backModal) backHeaderView.addSubview(emotionView) backHeaderView.snp.makeConstraints { @@ -105,6 +175,10 @@ class AAnswerViewController: BaseViewController { $0.height.equalTo(77) } + backModal.snp.makeConstraints { + $0.edges.equalToSuperview() + } + emotionView.snp.makeConstraints { $0.centerX.equalToSuperview() $0.height.equalTo(44) @@ -130,7 +204,7 @@ class AAnswerViewController: BaseViewController { answerBottomView.snp.makeConstraints { $0.top.equalTo(answerTextView.snp.bottom) - $0.bottom.equalTo(view.keyboardLayoutGuide).inset(34) + $0.bottom.equalTo(view.keyboardLayoutGuide.snp.top) $0.horizontalEdges.equalToSuperview() $0.height.equalTo(72) } @@ -180,6 +254,11 @@ extension AAnswerViewController { emotionSheetView.showOpenAnimation() } + private func showBackModal() { + backModal.isHidden = false + backModal.showOpenAnimation() + } + private func setPremium() { backHeaderView.do { $0.setRightSecondButton(image: UIImage(named: "Switch")) diff --git a/TellingMe/tellingMe/presentation/answer/viewModel/AnswerViewModel.swift b/TellingMe/tellingMe/presentation/answer/viewModel/AnswerViewModel.swift index 7b77ca95..c4e1495c 100644 --- a/TellingMe/tellingMe/presentation/answer/viewModel/AnswerViewModel.swift +++ b/TellingMe/tellingMe/presentation/answer/viewModel/AnswerViewModel.swift @@ -9,26 +9,25 @@ import Foundation import RxCocoa import RxSwift +import Moya protocol AnswerViewModelInputs { -// var clickedChangeQuestion -// var clickedFoldView -// var clickedBackNavigation -// var inputTextField -// var toggleSwitch -// var clickedRegisterButton + var toggleSwitch: BehaviorRelay { get } + var completeButtonTapped: PublishSubject { get } + var registerButtonTapped: PublishSubject { get } + var inputText: BehaviorRelay { get } func selectEmotion(indexPath: IndexPath) } protocol AnswerViewModelOutputs { var changeQuestionSubject: PublishSubject { get } - var foldViewSubject: BehaviorRelay { get } var inputTextRelay: BehaviorRelay { get } - var tolggleSwitchSubject: BehaviorRelay { get } var countTextRelay: BehaviorRelay { get } var toastSubject: PublishSubject { get } var questionSubject: PublishSubject { get } - var selectedEmotionIndexSubject: PublishSubject { get } + var selectedEmotionIndexSubject: BehaviorRelay { get } + var showEmotionSubject: PublishSubject { get } + var successRegisterSubject: PublishSubject { get } } protocol AnswerViewModelType { @@ -37,7 +36,6 @@ protocol AnswerViewModelType { } final class AnswerViewModel: AnswerViewModelType, AnswerViewModelInputs, AnswerViewModelOutputs { - // 옛날꺼 var questionDate: String? = Date().getQuestionDate() var modalChanged: Int = 0 @@ -53,29 +51,74 @@ final class AnswerViewModel: AnswerViewModelType, AnswerViewModelInputs, AnswerV // inputs var inputs: AnswerViewModelInputs { return self } + var toggleSwitch = BehaviorRelay(value: true) + var completeButtonTapped = PublishSubject() + var registerButtonTapped = PublishSubject() + var inputText = BehaviorRelay(value: "") + func selectEmotion(indexPath: IndexPath) { - selectedEmotionIndexSubject.onNext(indexPath) + selectedEmotionIndexSubject.accept(indexPath) } // outputs var outputs: AnswerViewModelOutputs { return self } var changeQuestionSubject: PublishSubject = PublishSubject() - var foldViewSubject = BehaviorRelay(value: false) var inputTextRelay = BehaviorRelay(value: "") - var tolggleSwitchSubject = BehaviorRelay(value: ()) - var countTextRelay = BehaviorRelay(value: "") + var countTextRelay = BehaviorRelay(value: "0") var toastSubject = PublishSubject() var questionSubject = PublishSubject() - var selectedEmotionIndexSubject = PublishSubject() + var selectedEmotionIndexSubject = BehaviorRelay(value: IndexPath(row: 1, section: 0)) + var showEmotionSubject = PublishSubject() + var successRegisterSubject = PublishSubject() init() { getQuestion() + completeButtonTapped + .subscribe(onNext: { [weak self] _ in + guard let self else { return } + self.tapRegisterButton() + }) + .disposed(by: disposeBag) + registerButtonTapped + .subscribe(onNext: { [weak self] _ in + guard let self else { return } + self.registerAnswer() + }) + .disposed(by: disposeBag) + inputText + .map { text -> String in + if text.count >= 300 { + self.toastSubject.onNext("300자까지만 작성 가능합니다.") + let truncatedText = String(text.prefix(300)) + return truncatedText + } + return text + } + .subscribe(onNext: { [weak self] text in + guard let self else { return } + self.outputs.countTextRelay.accept(String(text.count)) + self.outputs.inputTextRelay.accept(text) + }) + .disposed(by: disposeBag) } } extension AnswerViewModel { + private func tapRegisterButton() { + if inputText.value.count < 4 { + toastSubject.onNext("4글자 이상 입력하여 주세요.") + } else { + showEmotionSubject.onNext(()) + } + } + private func getQuestion() { - QuestionAPI.getTodayQuestion(query: "2023-11-29") + guard let date = questionDate else { + self.toastSubject.onNext("날짜에 맞는 질문을 찾을 수 없습니다.") + return + } + + QuestionAPI.getTodayQuestion(query: date) .map { response in return Question(date: response.date, question: response.title, phrase: response.phrase) } @@ -90,6 +133,25 @@ extension AnswerViewModel { } private func registerAnswer() { - + guard let date = questionDate else { + self.toastSubject.onNext("날짜에 맞는 질문을 찾을 수 없습니다.") + return + } + + let request = RegisterAnswerRequest(content: inputText.value, date: date, emotion: selectedEmotionIndexSubject.value.row + 1, isPublic: toggleSwitch.value, isSpare: false) + AnswerAPI.registerAnswer(request: request) + .subscribe(onNext: { [weak self] _ in + guard let self else { return } + self.successRegisterSubject.onNext(()) + }, onError: { [weak self] error in + guard let self else { return } + switch error { + case APIError.errorData(let errorData): + self.toastSubject.onNext(errorData.message) + default: + self.toastSubject.onNext("알 수 없는 오류가 발생했습니다.") + } + }) + .disposed(by: disposeBag) } } diff --git a/TellingMe/tellingMe/presentation/common/answer/AnswerTextView.swift b/TellingMe/tellingMe/presentation/common/answer/AnswerTextView.swift index 4cc8800b..edcf6e2f 100644 --- a/TellingMe/tellingMe/presentation/common/answer/AnswerTextView.swift +++ b/TellingMe/tellingMe/presentation/common/answer/AnswerTextView.swift @@ -8,6 +8,8 @@ import Foundation import UIKit +import RxCocoa + class AnswerTextView: UIView { let textView: UITextView = { let textView = UITextView() @@ -15,6 +17,10 @@ class AnswerTextView: UIView { textView.translatesAutoresizingMaskIntoConstraints = false return textView }() + + var textViewRxText: ControlProperty { + return textView.rx.text + } override init(frame: CGRect) { super.init(frame: frame) diff --git a/TellingMe/tellingMe/presentation/common/emotion/EmotionView.swift b/TellingMe/tellingMe/presentation/common/emotion/EmotionView.swift index 3deea828..25d555a4 100644 --- a/TellingMe/tellingMe/presentation/common/emotion/EmotionView.swift +++ b/TellingMe/tellingMe/presentation/common/emotion/EmotionView.swift @@ -65,4 +65,9 @@ class EmotionView: UIView { emotionLabel.text = emotions[index - 1].text emotionImageView.image = UIImage(named: emotions[index - 1].image) } + + func setEmotion(emotion: Emotions) { + emotionLabel.text = emotion.stringValue + emotionImageView.image = UIImage(named: emotion.rawValue) + } } diff --git a/TellingMe/tellingMe/presentation/common/modal/MModalView.swift b/TellingMe/tellingMe/presentation/common/modal/MModalView.swift new file mode 100644 index 00000000..8ad73a7d --- /dev/null +++ b/TellingMe/tellingMe/presentation/common/modal/MModalView.swift @@ -0,0 +1,112 @@ +// +// MModalView.swift +// tellingMe +// +// Created by 마경미 on 06.12.23. +// + +import UIKit + +import RxSwift +import SnapKit +import Then + +final class MModalView: BBaseView { + private let contentView = UIView() + private let titleLabel = UILabel() + private let subTitleLabel = UILabel() + private let buttonStackView = UIStackView() + private let leftButton = TeritaryTextButton() + private let rightButton = SecondaryTextButton() + + var leftButtonTapObservable: Observable { + return leftButton.rx.tap.asObservable() + } + + var rightButtonTapObservable: Observable { + return rightButton.rx.tap.asObservable() + } + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func setStyles() { + backgroundColor = .AlphaBlackColor + + contentView.do { + $0.backgroundColor = .Side100 + $0.layer.cornerRadius = 20 + } + + titleLabel.do { + $0.font = .fontNanum(.B1_Regular) + $0.textAlignment = .center + $0.textColor = .Black + } + + subTitleLabel.do { + $0.font = .fontNanum(.B2_Regular) + $0.textAlignment = .center + $0.textColor = .Gray7 + } + + buttonStackView.do { + $0.distribution = .fillEqually + $0.spacing = 15 + } + } + + override func setLayout() { + addSubview(contentView) + contentView.addSubviews(titleLabel, subTitleLabel, buttonStackView) + buttonStackView.addArrangedSubviews(leftButton, rightButton) + + contentView.snp.makeConstraints { + $0.center.equalToSuperview() + $0.horizontalEdges.equalToSuperview().inset(25) + } + + titleLabel.snp.makeConstraints { + $0.top.equalToSuperview().inset(30) + $0.horizontalEdges.equalToSuperview().inset(20) + $0.height.equalTo(17) + } + + subTitleLabel.snp.makeConstraints { + $0.top.equalTo(titleLabel.snp.bottom).offset(8) + $0.horizontalEdges.equalToSuperview().inset(20) + $0.height.equalTo(16) + } + + buttonStackView.snp.makeConstraints { + $0.top.equalTo(subTitleLabel.snp.bottom).offset(28) + $0.horizontalEdges.equalToSuperview().inset(20) + $0.height.equalTo(55) + $0.bottom.equalToSuperview().inset(20) + } + } +} + +extension MModalView { + func setModalButton(leftButtonTitle: String, rightButtonTitle: String) { + leftButton.setText(text: leftButtonTitle) + rightButton.setText(text: rightButtonTitle) + } + + func setModalTitle(title: String, subTitle: String) { + titleLabel.text = title + subTitleLabel.text = subTitle + } + + func showOpenAnimation() { + contentView.transform = CGAffineTransform(translationX: 0, y: contentView.frame.height) + UIView.animate(withDuration: 0.3) { [weak self] in + self?.contentView.transform = .identity + } + } +} diff --git a/TellingMe/tellingMe/presentation/communication/viewControllers/CommunicationListViewController.swift b/TellingMe/tellingMe/presentation/communication/viewControllers/CommunicationListViewController.swift index f656a387..5cddf696 100644 --- a/TellingMe/tellingMe/presentation/communication/viewControllers/CommunicationListViewController.swift +++ b/TellingMe/tellingMe/presentation/communication/viewControllers/CommunicationListViewController.swift @@ -102,8 +102,8 @@ class CommunicationListViewController: UIViewController { reloadCollectionView() }).disposed(by: disposeBag) viewModel.answerSuccessSubject - .subscribe(onNext: { [weak self] response in - self?.pushCommunicationAnswer(response) + .subscribe(onNext: { [weak self] indexPath in + self?.pushCommunicationAnswer(indexPath) // self?.collectionView.isUserInteractionEnabled = true }).disposed(by: disposeBag) viewModel.showToastSubject diff --git a/TellingMe/tellingMe/util/nameSpace/Emotions.swift b/TellingMe/tellingMe/util/nameSpace/Emotions.swift index c5de8fea..12f2ba49 100644 --- a/TellingMe/tellingMe/util/nameSpace/Emotions.swift +++ b/TellingMe/tellingMe/util/nameSpace/Emotions.swift @@ -123,22 +123,22 @@ enum Emotions: String { } } - init?(intValue: Int) { + init(intValue: Int) { switch intValue { - case 0: - self = .happy case 1: - self = .proud + self = .happy case 2: - self = .meh + self = .proud case 3: - self = .tired + self = .meh case 4: - self = .sad + self = .tired case 5: + self = .sad + case 6: self = .angry default: - return nil + self = .happy } }