From a5c610487e13233b400ad094c743976f4e4c1fda Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 9 Dec 2024 21:52:33 +0900 Subject: [PATCH 01/10] =?UTF-8?q?chore/#404=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EA=B0=84=EB=8B=A8=ED=95=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/SetReadyInfoViewController.swift | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 7e889abf..111a0156 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -31,16 +31,13 @@ final class SetReadyInfoViewController: BaseViewController { // MARK: - LifeCycle override func loadView() { - self.view = rootView + view = rootView } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white - setupNavigationBarBackButton() - setupNavigationBarTitle(with: "준비 정보 입력하기") - setupBinding() setupTapGesture() setupTextField() @@ -52,6 +49,11 @@ final class SetReadyInfoViewController: BaseViewController { navigationController?.isNavigationBarHidden = false } + override func setupView() { + setupNavigationBarBackButton() + setupNavigationBarTitle(with: "준비 정보 입력하기") + } + override func setupDelegate() { setTextFieldDelegate() } @@ -109,7 +111,8 @@ final class SetReadyInfoViewController: BaseViewController { view.addGestureRecognizer(tapGesture) } - @objc private func dismissKeyboard() { + @objc + private func dismissKeyboard() { view.endEditing(true) } } From e73e46c90621923d6cacba4e92626332dffd571c Mon Sep 17 00:00:00 2001 From: mmaybei Date: Tue, 10 Dec 2024 00:03:33 +0900 Subject: [PATCH 02/10] =?UTF-8?q?refactor/#404=20=ED=85=8D=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=ED=95=84=EB=93=9C=20border=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20Rx=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 111a0156..f6772b9d 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -7,13 +7,18 @@ import UIKit +import RxCocoa +import RxSwift + final class SetReadyInfoViewController: BaseViewController { // MARK: - Property private let rootView = SetReadyInfoView() + private let viewModel: SetReadyInfoViewModel + private let disposeBag = DisposeBag() // MARK: - Initializer @@ -59,6 +64,11 @@ final class SetReadyInfoViewController: BaseViewController { } override func setupAction() { + setupTextField(textField: rootView.readyHourTextField) + setupTextField(textField: rootView.readyMinuteTextField) + setupTextField(textField: rootView.moveHourTextField) + setupTextField(textField: rootView.moveMinuteTextField) + rootView.readyHourTextField.addTarget( self, action: #selector(textFieldDidChange), @@ -86,6 +96,20 @@ final class SetReadyInfoViewController: BaseViewController { ) } + private func setupTextField(textField: UITextField) { + let textFieldEvent = Observable.merge( + textField.rx.controlEvent(.editingDidBegin).map { UIColor.maincolor.cgColor }, + textField.rx.controlEvent(.editingDidEnd).map { UIColor.gray3.cgColor }, + textField.rx.controlEvent(.editingDidEndOnExit).map { UIColor.gray3.cgColor } + ) + + textFieldEvent + .bind { borderColor in + textField.layer.borderColor = borderColor + } + .disposed(by: disposeBag) + } + @objc private func textFieldDidChange(_ textField: UITextField) { let text = textField.text ?? "" @@ -121,21 +145,6 @@ final class SetReadyInfoViewController: BaseViewController { // MARK: - UITextFieldDelegate extension SetReadyInfoViewController: UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { - textField.layer.borderColor = UIColor.maincolor.cgColor - } - - func textFieldDidEndEditing(_ textField: UITextField) { - textField.layer.borderColor = UIColor.gray3.cgColor - - if let text = textField.text, !text.isEmpty { - viewModel.updateTime( - textField: textField.accessibilityIdentifier ?? "", - time: textField.text ?? "" - ) - } - } - func textField( _ textField: UITextField, shouldChangeCharactersIn range: NSRange, From cb7b5fd0e689c5e38b033e0f126e8cefbce54f38 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Tue, 10 Dec 2024 03:32:15 +0900 Subject: [PATCH 03/10] =?UTF-8?q?refactor/#404=20=ED=85=8D=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=ED=95=84=EB=93=9C=20=EC=A1=B0=EA=B1=B4=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=20=EB=B0=8F=20=EC=9E=85=EB=A0=A5=20=EC=A0=9C=ED=95=9C?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20Rx=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 94 +++++++------- .../ViewModel/SetReadyInfoViewModel.swift | 116 +++++++++++++----- 2 files changed, 128 insertions(+), 82 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index f6772b9d..5f54d4c5 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -46,6 +46,7 @@ final class SetReadyInfoViewController: BaseViewController { setupBinding() setupTapGesture() setupTextField() + bindViewModel() } override func viewWillAppear(_ animated: Bool) { @@ -69,26 +70,6 @@ final class SetReadyInfoViewController: BaseViewController { setupTextField(textField: rootView.moveHourTextField) setupTextField(textField: rootView.moveMinuteTextField) - rootView.readyHourTextField.addTarget( - self, - action: #selector(textFieldDidChange), - for: .editingChanged - ) - rootView.readyMinuteTextField.addTarget( - self, - action: #selector(textFieldDidChange), - for: .editingChanged - ) - rootView.moveHourTextField.addTarget( - self, - action: #selector(textFieldDidChange), - for: .editingChanged - ) - rootView.moveMinuteTextField.addTarget( - self, - action: #selector(textFieldDidChange), - for: .editingChanged - ) rootView.doneButton.addTarget( self, action: #selector(doneButtonDidTap), @@ -96,6 +77,41 @@ final class SetReadyInfoViewController: BaseViewController { ) } + private func bindViewModel() { + let input = SetReadyInfoViewModel.Input( + readyHourText: rootView.readyHourTextField.rx.text.orEmpty.asObservable(), + readyMinuteText: rootView.readyMinuteTextField.rx.text.orEmpty.asObservable(), + moveHourText: rootView.moveHourTextField.rx.text.orEmpty.asObservable(), + moveMinuteText: rootView.moveMinuteTextField.rx.text.orEmpty.asObservable() + ) + + let output = viewModel.transform(input: input, disposeBag: disposeBag) + + output.readyHourText + .drive(with: self) { owner, text in + owner.rootView.readyHourTextField.text = text + } + .disposed(by: disposeBag) + + output.readyMinuteText + .drive(with: self) { owner, text in + owner.rootView.readyMinuteTextField.text = text + } + .disposed(by: disposeBag) + + output.moveHourText + .drive(with: self) { owner, text in + owner.rootView.moveHourTextField.text = text + } + .disposed(by: disposeBag) + + output.moveMinuteText + .drive(with: self) { owner, text in + owner.rootView.moveMinuteTextField.text = text + } + .disposed(by: disposeBag) + } + private func setupTextField(textField: UITextField) { let textFieldEvent = Observable.merge( textField.rx.controlEvent(.editingDidBegin).map { UIColor.maincolor.cgColor }, @@ -110,18 +126,6 @@ final class SetReadyInfoViewController: BaseViewController { .disposed(by: disposeBag) } - @objc - private func textFieldDidChange(_ textField: UITextField) { - let text = textField.text ?? "" - viewModel.updateTime(textField: textField.accessibilityIdentifier ?? "", time: text) - viewModel.checkValid( - readyHourText: rootView.readyHourTextField.text ?? "", - readyMinuteText: rootView.readyMinuteTextField.text ?? "", - moveHourText: rootView.moveHourTextField.text ?? "", - moveMinuteText: rootView.moveMinuteTextField.text ?? "" - ) - } - @objc private func doneButtonDidTap(_ sender: UIButton) { viewModel.updateReadyInfo() @@ -204,31 +208,15 @@ private extension SetReadyInfoViewController { // MARK: - Data Bind func setupBinding() { - viewModel.readyHour.bind { [weak self] readyHour in - self?.rootView.readyHourTextField.text = readyHour - } - - viewModel.readyMinute.bind { [weak self] readyMinute in - self?.rootView.readyMinuteTextField.text = readyMinute - } - - viewModel.moveHour.bind { [weak self] moveHour in - self?.rootView.moveHourTextField.text = moveHour - } - - viewModel.moveMinute.bind { [weak self] moveMinute in - self?.rootView.moveMinuteTextField.text = moveMinute - } - viewModel.isValid.bind { [weak self] isValid in self?.rootView.doneButton.isEnabled = isValid } - viewModel.errMessage.bind { [weak self] err in - if !err.isEmpty { - self?.showToast(err) - } - } +// viewModel.errMessage.bind { [weak self] err in +// if !err.isEmpty { +// self?.showToast(err) +// } +// } viewModel.isSucceedToSave.bind { [weak self] _ in if self?.viewModel.isSucceedToSave.value == true { diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index 60918e1d..58a3fa8b 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -8,15 +8,28 @@ import Foundation import UserNotifications +import RxCocoa +import RxSwift + +enum Time { + case hour + case minute +} + final class SetReadyInfoViewModel { let promiseID: Int let promiseName: String let promiseTime: String let isValid = ObservablePattern(false) - let errMessage = ObservablePattern("") let isSucceedToSave = ObservablePattern(false) + var errMessage: String = "" + + let readyHourRelay = BehaviorRelay(value: 0) + let readyMinuteRelay = BehaviorRelay(value: 0) + let moveHourRelay = BehaviorRelay(value: 0) + let moveMinuteRelay = BehaviorRelay(value: 0) var readyHour = ObservablePattern("") var readyMinute = ObservablePattern("") @@ -53,15 +66,6 @@ final class SetReadyInfoViewModel { self.notificationManager = notificationManager } - private func validTime(time: Int, range: ClosedRange, defaultValue: String) -> String { - if range.contains(time) { - return String(time) - } else { - errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - return defaultValue - } - } - private func calculateTimes() { let readyHours = Int(readyHour.value) ?? storedReadyHour let readyMinutes = Int(readyMinute.value) ?? storedReadyMinute @@ -72,25 +76,6 @@ final class SetReadyInfoViewModel { moveTime = moveHours * 60 + moveMinutes } - func updateTime(textField: String, time: String) { - guard let time = Int(time) else { return } - - switch textField { - case "readyHour": - readyHour.value = validTime(time: time, range: 0...23, defaultValue: "23") - case "readyMinute": - readyMinute.value = validTime(time: time, range: 0...59, defaultValue: "59") - case "moveHour": - moveHour.value = validTime(time: time, range: 0...23, defaultValue: "23") - case "moveMinute": - moveMinute.value = validTime(time: time, range: 0...59, defaultValue: "59") - default: - break - } - - calculateTimes() - } - func checkValid(readyHourText: String, readyMinuteText: String, moveHourText: String, @@ -209,3 +194,76 @@ final class SetReadyInfoViewModel { } } } + +extension SetReadyInfoViewModel: ViewModelType { + struct Input { + let readyHourText: Observable + let readyMinuteText: Observable + let moveHourText: Observable + let moveMinuteText: Observable + } + + struct Output { + let readyHourText: Driver + let readyMinuteText: Driver + let moveHourText: Driver + let moveMinuteText: Driver + } + + func transform(input: Input, disposeBag: RxSwift.DisposeBag) -> Output { + input.readyHourText + .distinctUntilChanged() + .compactMap { Int($0) } + .bind(to: readyHourRelay) + .disposed(by: disposeBag) + + input.readyMinuteText + .distinctUntilChanged() + .compactMap { Int($0) } + .bind(to: readyMinuteRelay) + .disposed(by: disposeBag) + + input.moveHourText + .distinctUntilChanged() + .compactMap { Int($0) } + .bind(to: moveHourRelay) + .disposed(by: disposeBag) + + input.moveMinuteText + .distinctUntilChanged() + .compactMap { Int($0) } + .bind(to: moveMinuteRelay) + .disposed(by: disposeBag) + + let readyHourText = checkValidTime(time: .hour, relay: readyHourRelay) + let readyMinuteText = checkValidTime(time: .minute, relay: readyMinuteRelay) + let moveHourText = checkValidTime(time: .hour, relay: moveHourRelay) + let moveMinuteText = checkValidTime(time: .minute, relay: moveMinuteRelay) + + let output = Output( + readyHourText: readyHourText, + readyMinuteText: readyMinuteText, + moveHourText: moveHourText, + moveMinuteText: moveMinuteText + ) + + return output + } +} + +private extension SetReadyInfoViewModel { + func checkValidTime(time: Time, relay: BehaviorRelay) -> Driver { + let range: ClosedRange = time == .hour ? 0...23 : 0...59 + return relay + .map { value in + if range.contains(value) { + return value.description + } else { + self.errMessage = "시간은 23시간 59분까지만 입력할 수 있어요!" + print(self.errMessage) + return String(range.upperBound) + } + } + .asDriver(onErrorJustReturn: "0") + } +} From 2b75a1cc53a3c414d9ea12f23b1080980778d889 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Tue, 10 Dec 2024 14:17:38 +0900 Subject: [PATCH 04/10] =?UTF-8?q?refactor/#404=20=EC=99=84=EB=A3=8C=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=ED=99=9C=EC=84=B1=ED=99=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20Rx=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 18 +- .../ViewModel/SetReadyInfoViewModel.swift | 181 +++++++++--------- 2 files changed, 96 insertions(+), 103 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 5f54d4c5..7bcf1496 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -110,6 +110,13 @@ final class SetReadyInfoViewController: BaseViewController { owner.rootView.moveMinuteTextField.text = text } .disposed(by: disposeBag) + + output.doneButtonIsEnabled + .drive(with: self) { owner, isEnabled in + owner.rootView.doneButton.backgroundColor = isEnabled ? .maincolor : .gray2 + owner.rootView.doneButton.isEnabled = isEnabled + } + .disposed(by: disposeBag) } private func setupTextField(textField: UITextField) { @@ -176,13 +183,6 @@ private extension SetReadyInfoViewController { rootView.moveHourTextField.text = String(viewModel.storedMoveHour) rootView.moveMinuteTextField.text = String(viewModel.storedMoveMinute) } - - viewModel.checkValid( - readyHourText: rootView.readyHourTextField.text ?? "", - readyMinuteText: rootView.readyMinuteTextField.text ?? "", - moveHourText: rootView.moveHourTextField.text ?? "", - moveMinuteText: rootView.moveMinuteTextField.text ?? "" - ) } func setTextFieldDelegate() { @@ -208,10 +208,6 @@ private extension SetReadyInfoViewController { // MARK: - Data Bind func setupBinding() { - viewModel.isValid.bind { [weak self] isValid in - self?.rootView.doneButton.isEnabled = isValid - } - // viewModel.errMessage.bind { [weak self] err in // if !err.isEmpty { // self?.showToast(err) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index 58a3fa8b..3e13be78 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -21,15 +21,14 @@ final class SetReadyInfoViewModel { let promiseName: String let promiseTime: String - let isValid = ObservablePattern(false) let isSucceedToSave = ObservablePattern(false) var errMessage: String = "" - let readyHourRelay = BehaviorRelay(value: 0) - let readyMinuteRelay = BehaviorRelay(value: 0) - let moveHourRelay = BehaviorRelay(value: 0) - let moveMinuteRelay = BehaviorRelay(value: 0) + let readyHourRelay = BehaviorRelay(value: "") + let readyMinuteRelay = BehaviorRelay(value: "") + let moveHourRelay = BehaviorRelay(value: "") + let moveMinuteRelay = BehaviorRelay(value: "") var readyHour = ObservablePattern("") var readyMinute = ObservablePattern("") @@ -76,19 +75,6 @@ final class SetReadyInfoViewModel { moveTime = moveHours * 60 + moveMinutes } - func checkValid(readyHourText: String, - readyMinuteText: String, - moveHourText: String, - moveMinuteText: String - ) { - if !readyHourText.isEmpty && !readyMinuteText.isEmpty - && !moveHourText.isEmpty && !moveMinuteText.isEmpty { - isValid.value = true - } else { - isValid.value = false - } - } - func updateReadyInfo() { calculateTimes() @@ -115,8 +101,92 @@ final class SetReadyInfoViewModel { } } } +} + +extension SetReadyInfoViewModel: ViewModelType { + struct Input { + let readyHourText: Observable + let readyMinuteText: Observable + let moveHourText: Observable + let moveMinuteText: Observable + } - private func scheduleLocalNotification() { + struct Output { + let readyHourText: Driver + let readyMinuteText: Driver + let moveHourText: Driver + let moveMinuteText: Driver + let doneButtonIsEnabled: Driver + } + + func transform(input: Input, disposeBag: RxSwift.DisposeBag) -> Output { + input.readyHourText + .distinctUntilChanged() + .bind(to: readyHourRelay) + .disposed(by: disposeBag) + + input.readyMinuteText + .distinctUntilChanged() + .bind(to: readyMinuteRelay) + .disposed(by: disposeBag) + + input.moveHourText + .distinctUntilChanged() + .bind(to: moveHourRelay) + .disposed(by: disposeBag) + + input.moveMinuteText + .distinctUntilChanged() + .bind(to: moveMinuteRelay) + .disposed(by: disposeBag) + + let readyHourText = checkValidTime(time: .hour, relay: readyHourRelay) + let readyMinuteText = checkValidTime(time: .minute, relay: readyMinuteRelay) + let moveHourText = checkValidTime(time: .hour, relay: moveHourRelay) + let moveMinuteText = checkValidTime(time: .minute, relay: moveMinuteRelay) + + let doneButtonIsEnabled = Observable.combineLatest( + readyHourRelay.map { !$0.isEmpty }, + readyMinuteRelay.map { !$0.isEmpty }, + moveHourRelay.map { !$0.isEmpty }, + moveMinuteRelay.map { !$0.isEmpty } + ) + .map { $0 && $1 && $2 && $3 } + .asDriver(onErrorJustReturn: false) + + let output = Output( + readyHourText: readyHourText, + readyMinuteText: readyMinuteText, + moveHourText: moveHourText, + moveMinuteText: moveMinuteText, + doneButtonIsEnabled: doneButtonIsEnabled + ) + + return output + } +} + +private extension SetReadyInfoViewModel { + func checkValidTime(time: Time, relay: BehaviorRelay) -> Driver { + let range: ClosedRange = time == .hour ? 0...23 : 0...59 + return relay + .map { value in + if value.isEmpty { + return "" + } else if let intValue = Int(value), range.contains(intValue) { + return value.description + } else { + self.errMessage = "시간은 23시간 59분까지만 입력할 수 있어요!" + print(self.errMessage) + return String(range.upperBound) + } + } + .asDriver(onErrorJustReturn: "") + } +} + +private extension SetReadyInfoViewModel { + func scheduleLocalNotification() { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" dateFormatter.locale = Locale(identifier: "ko_KR") @@ -194,76 +264,3 @@ final class SetReadyInfoViewModel { } } } - -extension SetReadyInfoViewModel: ViewModelType { - struct Input { - let readyHourText: Observable - let readyMinuteText: Observable - let moveHourText: Observable - let moveMinuteText: Observable - } - - struct Output { - let readyHourText: Driver - let readyMinuteText: Driver - let moveHourText: Driver - let moveMinuteText: Driver - } - - func transform(input: Input, disposeBag: RxSwift.DisposeBag) -> Output { - input.readyHourText - .distinctUntilChanged() - .compactMap { Int($0) } - .bind(to: readyHourRelay) - .disposed(by: disposeBag) - - input.readyMinuteText - .distinctUntilChanged() - .compactMap { Int($0) } - .bind(to: readyMinuteRelay) - .disposed(by: disposeBag) - - input.moveHourText - .distinctUntilChanged() - .compactMap { Int($0) } - .bind(to: moveHourRelay) - .disposed(by: disposeBag) - - input.moveMinuteText - .distinctUntilChanged() - .compactMap { Int($0) } - .bind(to: moveMinuteRelay) - .disposed(by: disposeBag) - - let readyHourText = checkValidTime(time: .hour, relay: readyHourRelay) - let readyMinuteText = checkValidTime(time: .minute, relay: readyMinuteRelay) - let moveHourText = checkValidTime(time: .hour, relay: moveHourRelay) - let moveMinuteText = checkValidTime(time: .minute, relay: moveMinuteRelay) - - let output = Output( - readyHourText: readyHourText, - readyMinuteText: readyMinuteText, - moveHourText: moveHourText, - moveMinuteText: moveMinuteText - ) - - return output - } -} - -private extension SetReadyInfoViewModel { - func checkValidTime(time: Time, relay: BehaviorRelay) -> Driver { - let range: ClosedRange = time == .hour ? 0...23 : 0...59 - return relay - .map { value in - if range.contains(value) { - return value.description - } else { - self.errMessage = "시간은 23시간 59분까지만 입력할 수 있어요!" - print(self.errMessage) - return String(range.upperBound) - } - } - .asDriver(onErrorJustReturn: "0") - } -} From 2cf89faff28f9ba6a6147302d352c07627b0bfb3 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Tue, 10 Dec 2024 14:33:59 +0900 Subject: [PATCH 05/10] =?UTF-8?q?refactor/#404=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 22 +++++++++---------- .../ViewModel/SetReadyInfoViewModel.swift | 9 +++++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 7bcf1496..960f0720 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -111,6 +111,12 @@ final class SetReadyInfoViewController: BaseViewController { } .disposed(by: disposeBag) + output.errMessage + .drive(with: self) { owner, err in + owner.showToast(err) + } + .disposed(by: disposeBag) + output.doneButtonIsEnabled .drive(with: self) { owner, isEnabled in owner.rootView.doneButton.backgroundColor = isEnabled ? .maincolor : .gray2 @@ -133,6 +139,11 @@ final class SetReadyInfoViewController: BaseViewController { .disposed(by: disposeBag) } + func showToast(_ message: String, bottomInset: CGFloat = 128) { + guard let view else { return } + Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) + } + @objc private func doneButtonDidTap(_ sender: UIButton) { viewModel.updateReadyInfo() @@ -200,20 +211,9 @@ private extension SetReadyInfoViewController { } } - func showToast(_ message: String, bottomInset: CGFloat = 128) { - guard let view else { return } - Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) - } - // MARK: - Data Bind func setupBinding() { -// viewModel.errMessage.bind { [weak self] err in -// if !err.isEmpty { -// self?.showToast(err) -// } -// } - viewModel.isSucceedToSave.bind { [weak self] _ in if self?.viewModel.isSucceedToSave.value == true { DispatchQueue.main.async { diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index 3e13be78..18707bdd 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -23,7 +23,7 @@ final class SetReadyInfoViewModel { let isSucceedToSave = ObservablePattern(false) - var errMessage: String = "" + var errMessageRelay = PublishRelay() let readyHourRelay = BehaviorRelay(value: "") let readyMinuteRelay = BehaviorRelay(value: "") @@ -116,6 +116,7 @@ extension SetReadyInfoViewModel: ViewModelType { let readyMinuteText: Driver let moveHourText: Driver let moveMinuteText: Driver + let errMessage: Driver let doneButtonIsEnabled: Driver } @@ -145,6 +146,8 @@ extension SetReadyInfoViewModel: ViewModelType { let moveHourText = checkValidTime(time: .hour, relay: moveHourRelay) let moveMinuteText = checkValidTime(time: .minute, relay: moveMinuteRelay) + let errMessage = errMessageRelay.asDriver(onErrorJustReturn: "") + let doneButtonIsEnabled = Observable.combineLatest( readyHourRelay.map { !$0.isEmpty }, readyMinuteRelay.map { !$0.isEmpty }, @@ -159,6 +162,7 @@ extension SetReadyInfoViewModel: ViewModelType { readyMinuteText: readyMinuteText, moveHourText: moveHourText, moveMinuteText: moveMinuteText, + errMessage: errMessage, doneButtonIsEnabled: doneButtonIsEnabled ) @@ -176,8 +180,7 @@ private extension SetReadyInfoViewModel { } else if let intValue = Int(value), range.contains(intValue) { return value.description } else { - self.errMessage = "시간은 23시간 59분까지만 입력할 수 있어요!" - print(self.errMessage) + self.errMessageRelay.accept("시간은 23시간 59분까지만 입력할 수 있어요!") return String(range.upperBound) } } From e414948c98545ad9ed9dc4ecdeadbc11946a594e Mon Sep 17 00:00:00 2001 From: mmaybei Date: Wed, 11 Dec 2024 00:25:21 +0900 Subject: [PATCH 06/10] =?UTF-8?q?refactor/#404=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20POST=20API=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20Rx=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 49 ++++----- .../ViewModel/SetReadyInfoViewModel.swift | 102 +++++++++--------- 2 files changed, 70 insertions(+), 81 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 960f0720..10a36455 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -43,7 +43,6 @@ final class SetReadyInfoViewController: BaseViewController { super.viewDidLoad() view.backgroundColor = .white - setupBinding() setupTapGesture() setupTextField() bindViewModel() @@ -69,12 +68,6 @@ final class SetReadyInfoViewController: BaseViewController { setupTextField(textField: rootView.readyMinuteTextField) setupTextField(textField: rootView.moveHourTextField) setupTextField(textField: rootView.moveMinuteTextField) - - rootView.doneButton.addTarget( - self, - action: #selector(doneButtonDidTap), - for: .touchUpInside - ) } private func bindViewModel() { @@ -82,7 +75,8 @@ final class SetReadyInfoViewController: BaseViewController { readyHourText: rootView.readyHourTextField.rx.text.orEmpty.asObservable(), readyMinuteText: rootView.readyMinuteTextField.rx.text.orEmpty.asObservable(), moveHourText: rootView.moveHourTextField.rx.text.orEmpty.asObservable(), - moveMinuteText: rootView.moveMinuteTextField.rx.text.orEmpty.asObservable() + moveMinuteText: rootView.moveMinuteTextField.rx.text.orEmpty.asObservable(), + doneButtonDidTap: rootView.doneButton.rx.tap.asObservable() ) let output = viewModel.transform(input: input, disposeBag: disposeBag) @@ -123,6 +117,14 @@ final class SetReadyInfoViewController: BaseViewController { owner.rootView.doneButton.isEnabled = isEnabled } .disposed(by: disposeBag) + + output.isSucceed + .drive(with: self) { owner, isSucceed in + if isSucceed { + owner.navigateToSetReadyCompleted() + } + } + .disposed(by: disposeBag) } private func setupTextField(textField: UITextField) { @@ -139,14 +141,17 @@ final class SetReadyInfoViewController: BaseViewController { .disposed(by: disposeBag) } - func showToast(_ message: String, bottomInset: CGFloat = 128) { - guard let view else { return } - Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) + private func navigateToSetReadyCompleted() { + let setReadyCompletedViewController = SetReadyCompletedViewController() + self.navigationController?.pushViewController( + setReadyCompletedViewController, + animated: true + ) } - @objc - private func doneButtonDidTap(_ sender: UIButton) { - viewModel.updateReadyInfo() + private func showToast(_ message: String, bottomInset: CGFloat = 128) { + guard let view else { return } + Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) } @@ -210,20 +215,4 @@ private extension SetReadyInfoViewController { textField.accessibilityIdentifier = identifier } } - - // MARK: - Data Bind - - func setupBinding() { - viewModel.isSucceedToSave.bind { [weak self] _ in - if self?.viewModel.isSucceedToSave.value == true { - DispatchQueue.main.async { - let viewController = SetReadyCompletedViewController() - self?.navigationController?.pushViewController( - viewController, - animated: true - ) - } - } - } - } } diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index 18707bdd..651bcffe 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -21,33 +21,24 @@ final class SetReadyInfoViewModel { let promiseName: String let promiseTime: String - let isSucceedToSave = ObservablePattern(false) - - var errMessageRelay = PublishRelay() + let errMessageRelay = PublishRelay() + let isSucceedRelay = BehaviorRelay(value: false) let readyHourRelay = BehaviorRelay(value: "") let readyMinuteRelay = BehaviorRelay(value: "") let moveHourRelay = BehaviorRelay(value: "") let moveMinuteRelay = BehaviorRelay(value: "") - - var readyHour = ObservablePattern("") - var readyMinute = ObservablePattern("") - var moveHour = ObservablePattern("") - var moveMinute = ObservablePattern("") - - var preparationTime = ObservablePattern(0) - var travelTime = ObservablePattern(0) var storedReadyHour: Int = 0 var storedReadyMinute: Int = 0 var storedMoveHour: Int = 0 var storedMoveMinute: Int = 0 - - let bufferTime: TimeInterval = 10 * 60 var readyTime: Int = 0 var moveTime: Int = 0 + let bufferTime: TimeInterval = 10 * 60 + private let service: SetReadyStatusInfoServiceType private let notificationManager: LocalNotificationManager @@ -64,43 +55,6 @@ final class SetReadyInfoViewModel { self.service = service self.notificationManager = notificationManager } - - private func calculateTimes() { - let readyHours = Int(readyHour.value) ?? storedReadyHour - let readyMinutes = Int(readyMinute.value) ?? storedReadyMinute - let moveHours = Int(moveHour.value) ?? storedMoveHour - let moveMinutes = Int(moveMinute.value) ?? storedMoveMinute - - readyTime = readyHours * 60 + readyMinutes - moveTime = moveHours * 60 + moveMinutes - } - - func updateReadyInfo() { - calculateTimes() - - // 로컬 알림 설정 - scheduleLocalNotification() - - Task { - let model = MyPromiseReadyInfoModel( - preparationTime: readyTime, - travelTime: moveTime - ) - - do { - guard let responseBody = try await service.updateMyPromiseReadyStatus( - with: promiseID, - requestModel: model - ) else { - isSucceedToSave.value = false - return - } - isSucceedToSave.value = responseBody.success - } catch { - print(">>> \(error.localizedDescription) : \(#function)") - } - } - } } extension SetReadyInfoViewModel: ViewModelType { @@ -109,6 +63,7 @@ extension SetReadyInfoViewModel: ViewModelType { let readyMinuteText: Observable let moveHourText: Observable let moveMinuteText: Observable + let doneButtonDidTap: Observable } struct Output { @@ -118,6 +73,7 @@ extension SetReadyInfoViewModel: ViewModelType { let moveMinuteText: Driver let errMessage: Driver let doneButtonIsEnabled: Driver + let isSucceed: Driver } func transform(input: Input, disposeBag: RxSwift.DisposeBag) -> Output { @@ -141,6 +97,12 @@ extension SetReadyInfoViewModel: ViewModelType { .bind(to: moveMinuteRelay) .disposed(by: disposeBag) + input.doneButtonDidTap + .subscribe(with: self) { owner, _ in + owner.updateReadyInfo() + } + .disposed(by: disposeBag) + let readyHourText = checkValidTime(time: .hour, relay: readyHourRelay) let readyMinuteText = checkValidTime(time: .minute, relay: readyMinuteRelay) let moveHourText = checkValidTime(time: .hour, relay: moveHourRelay) @@ -157,13 +119,16 @@ extension SetReadyInfoViewModel: ViewModelType { .map { $0 && $1 && $2 && $3 } .asDriver(onErrorJustReturn: false) + let isSucceed = isSucceedRelay.asDriver(onErrorJustReturn: false) + let output = Output( readyHourText: readyHourText, readyMinuteText: readyMinuteText, moveHourText: moveHourText, moveMinuteText: moveMinuteText, errMessage: errMessage, - doneButtonIsEnabled: doneButtonIsEnabled + doneButtonIsEnabled: doneButtonIsEnabled, + isSucceed: isSucceed ) return output @@ -186,6 +151,41 @@ private extension SetReadyInfoViewModel { } .asDriver(onErrorJustReturn: "") } + + func calculateTotalTime() { + guard let readyHour = Int(readyHourRelay.value) else { return } + guard let readyMinute = Int(readyMinuteRelay.value) else { return } + guard let moveHour = Int(moveHourRelay.value) else { return } + guard let moveMinute = Int(moveMinuteRelay.value) else { return } + + readyTime = readyHour * 60 + readyMinute + moveTime = moveHour * 60 + moveMinute + } + + func updateReadyInfo() { + calculateTotalTime() + scheduleLocalNotification() + + Task { + let model = MyPromiseReadyInfoModel( + preparationTime: readyTime, + travelTime: moveTime + ) + + do { + guard let responseBody = try await service.updateMyPromiseReadyStatus( + with: promiseID, + requestModel: model + ) else { + isSucceedRelay.accept(false) + return + } + isSucceedRelay.accept(responseBody.success) + } catch { + print(">>> \(error.localizedDescription) : \(#function)") + } + } + } } private extension SetReadyInfoViewModel { From 69502febdbbbc02f0679dde477cb74d7a49b8355 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Wed, 11 Dec 2024 01:08:34 +0900 Subject: [PATCH 07/10] =?UTF-8?q?refactor/#404=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=ED=94=8C=EB=A1=9C=EC=9A=B0=20Rx=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyStatusViewController.swift | 9 ++-- .../SetReadyInfoViewController.swift | 52 ++++++------------- .../ViewModel/SetReadyInfoViewModel.swift | 15 ++++-- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index 46039132..fd529220 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -256,13 +256,12 @@ extension ReadyStatusViewController { service: PromiseService() ) - viewModel.storedReadyHour = preparationTime / 60 - viewModel.storedReadyMinute = preparationTime % 60 - viewModel.storedMoveHour = travelTime / 60 - viewModel.storedMoveMinute = travelTime % 60 + viewModel.storedReadyHour = (preparationTime / 60).description + viewModel.storedReadyMinute = (preparationTime % 60).description + viewModel.storedMoveHour = (travelTime / 60).description + viewModel.storedMoveMinute = (travelTime % 60).description let viewController = SetReadyInfoViewController(viewModel: viewModel) - navigationController?.pushViewController(viewController, animated: true) } diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 10a36455..20d9d6c4 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -44,8 +44,9 @@ final class SetReadyInfoViewController: BaseViewController { view.backgroundColor = .white setupTapGesture() - setupTextField() bindViewModel() + + viewModel.setupStroredTime() } override func viewWillAppear(_ animated: Bool) { @@ -154,6 +155,21 @@ final class SetReadyInfoViewController: BaseViewController { Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) } + private func setTextFieldDelegate() { + let textFields: [(UITextField, String)] = [ + (rootView.readyHourTextField, "readyHour"), + (rootView.readyMinuteTextField, "readyMinute"), + (rootView.moveHourTextField, "moveHour"), + (rootView.moveMinuteTextField, "moveMinute") + ] + + textFields.forEach { (textField, identifier) in + textField.delegate = self + textField.keyboardType = .numberPad + textField.accessibilityIdentifier = identifier + } + } + // MARK: - Keyboard Dismissal @@ -182,37 +198,3 @@ extension SetReadyInfoViewController: UITextFieldDelegate { return allowedCharacters.isSuperset(of: characterSet) } } - - -// MARK: - Function - -private extension SetReadyInfoViewController { - func setupTextField() { - /// 저장된 준비 시간이 0이 아니면 텍스트 필드에 설정 - if viewModel.storedReadyHour != 0 || viewModel.storedReadyMinute != 0 { - rootView.readyHourTextField.text = String(viewModel.storedReadyHour) - rootView.readyMinuteTextField.text = String(viewModel.storedReadyMinute) - } - - /// 저장된 이동 시간이 0이 아니면 텍스트 필드에 설정 - if viewModel.storedMoveHour != 0 || viewModel.storedMoveMinute != 0 { - rootView.moveHourTextField.text = String(viewModel.storedMoveHour) - rootView.moveMinuteTextField.text = String(viewModel.storedMoveMinute) - } - } - - func setTextFieldDelegate() { - let textFields: [(UITextField, String)] = [ - (rootView.readyHourTextField, "readyHour"), - (rootView.readyMinuteTextField, "readyMinute"), - (rootView.moveHourTextField, "moveHour"), - (rootView.moveMinuteTextField, "moveMinute") - ] - - textFields.forEach { (textField, identifier) in - textField.delegate = self - textField.keyboardType = .numberPad - textField.accessibilityIdentifier = identifier - } - } -} diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index 651bcffe..b956375d 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -29,10 +29,10 @@ final class SetReadyInfoViewModel { let moveHourRelay = BehaviorRelay(value: "") let moveMinuteRelay = BehaviorRelay(value: "") - var storedReadyHour: Int = 0 - var storedReadyMinute: Int = 0 - var storedMoveHour: Int = 0 - var storedMoveMinute: Int = 0 + var storedReadyHour: String = "" + var storedReadyMinute: String = "" + var storedMoveHour: String = "" + var storedMoveMinute: String = "" var readyTime: Int = 0 var moveTime: Int = 0 @@ -55,6 +55,13 @@ final class SetReadyInfoViewModel { self.service = service self.notificationManager = notificationManager } + + func setupStroredTime() { + readyHourRelay.accept(storedReadyHour) + readyMinuteRelay.accept(storedReadyMinute) + moveHourRelay.accept(storedMoveHour) + moveMinuteRelay.accept(storedMoveMinute) + } } extension SetReadyInfoViewModel: ViewModelType { From e8f7def7cf9eee3d701cb0cb4f74c8a18cf1005f Mon Sep 17 00:00:00 2001 From: mmaybei Date: Wed, 11 Dec 2024 01:55:26 +0900 Subject: [PATCH 08/10] =?UTF-8?q?refactor/#404=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=EC=A4=80=EB=B9=84=EC=A0=95=EB=B3=B4=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/ReadyStatusViewController.swift | 9 ++++----- .../SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift | 8 ++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index fd529220..1efb0043 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -253,14 +253,13 @@ extension ReadyStatusViewController { promiseID: viewModel.promiseID, promiseTime: promiseTime, promiseName: promiseName, + storedReadyHour: (preparationTime / 60).description, + storedReadyMinute: (preparationTime % 60).description, + storedMoveHour: (travelTime / 60).description, + storedMoveMinute: (travelTime % 60).description, service: PromiseService() ) - viewModel.storedReadyHour = (preparationTime / 60).description - viewModel.storedReadyMinute = (preparationTime % 60).description - viewModel.storedMoveHour = (travelTime / 60).description - viewModel.storedMoveMinute = (travelTime % 60).description - let viewController = SetReadyInfoViewController(viewModel: viewModel) navigationController?.pushViewController(viewController, animated: true) } diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index b956375d..c14bdcbc 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -46,12 +46,20 @@ final class SetReadyInfoViewModel { promiseID: Int, promiseTime: String, promiseName: String, + storedReadyHour: String = "", + storedReadyMinute: String = "", + storedMoveHour: String = "", + storedMoveMinute: String = "", service: SetReadyStatusInfoServiceType, notificationManager: LocalNotificationManager = LocalNotificationManager.shared ) { self.promiseID = promiseID self.promiseName = promiseName self.promiseTime = promiseTime + self.storedReadyHour = storedReadyHour + self.storedReadyMinute = storedReadyMinute + self.storedMoveHour = storedMoveHour + self.storedMoveMinute = storedMoveMinute self.service = service self.notificationManager = notificationManager } From a8aa2dcf220b5fd65e0a152acd42e41c3ef9ea19 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Wed, 11 Dec 2024 02:05:36 +0900 Subject: [PATCH 09/10] =?UTF-8?q?refactor/#404=20viewWillAppear=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=EC=97=90=EC=84=9C=20=EA=B0=92=20?= =?UTF-8?q?=EC=A0=84=EB=8B=AC=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 5 +++-- .../ViewModel/SetReadyInfoViewModel.swift | 17 ++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 20d9d6c4..5ce4b8d4 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -18,6 +18,7 @@ final class SetReadyInfoViewController: BaseViewController { private let rootView = SetReadyInfoView() private let viewModel: SetReadyInfoViewModel + private let viewWillAppearRelay = PublishRelay() private let disposeBag = DisposeBag() @@ -45,14 +46,13 @@ final class SetReadyInfoViewController: BaseViewController { setupTapGesture() bindViewModel() - - viewModel.setupStroredTime() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.isNavigationBarHidden = false + viewWillAppearRelay.accept(()) } override func setupView() { @@ -73,6 +73,7 @@ final class SetReadyInfoViewController: BaseViewController { private func bindViewModel() { let input = SetReadyInfoViewModel.Input( + viewWillAppear: viewWillAppearRelay, readyHourText: rootView.readyHourTextField.rx.text.orEmpty.asObservable(), readyMinuteText: rootView.readyMinuteTextField.rx.text.orEmpty.asObservable(), moveHourText: rootView.moveHourTextField.rx.text.orEmpty.asObservable(), diff --git a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift index c14bdcbc..1f219cc0 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewModel/SetReadyInfoViewModel.swift @@ -63,17 +63,11 @@ final class SetReadyInfoViewModel { self.service = service self.notificationManager = notificationManager } - - func setupStroredTime() { - readyHourRelay.accept(storedReadyHour) - readyMinuteRelay.accept(storedReadyMinute) - moveHourRelay.accept(storedMoveHour) - moveMinuteRelay.accept(storedMoveMinute) - } } extension SetReadyInfoViewModel: ViewModelType { struct Input { + let viewWillAppear: PublishRelay let readyHourText: Observable let readyMinuteText: Observable let moveHourText: Observable @@ -92,6 +86,15 @@ extension SetReadyInfoViewModel: ViewModelType { } func transform(input: Input, disposeBag: RxSwift.DisposeBag) -> Output { + input.viewWillAppear + .subscribe(with: self) { owner, _ in + owner.readyHourRelay.accept(owner.storedReadyHour) + owner.readyMinuteRelay.accept(owner.storedReadyMinute) + owner.moveHourRelay.accept(owner.storedMoveHour) + owner.moveMinuteRelay.accept(owner.storedMoveMinute) + } + .disposed(by: disposeBag) + input.readyHourText .distinctUntilChanged() .bind(to: readyHourRelay) From 2d4fd59e8e8bfd5bb9d8ef7a7ceee432d8188e88 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Wed, 11 Dec 2024 02:11:35 +0900 Subject: [PATCH 10/10] =?UTF-8?q?refactor/#404=20=ED=82=A4=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=ED=83=AD=20=EC=A0=9C=EC=8A=A4=EC=B3=90=20Rx=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift index 5ce4b8d4..861712ba 100644 --- a/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/SetReadyInfo/ViewController/SetReadyInfoViewController.swift @@ -44,7 +44,6 @@ final class SetReadyInfoViewController: BaseViewController { super.viewDidLoad() view.backgroundColor = .white - setupTapGesture() bindViewModel() } @@ -69,6 +68,14 @@ final class SetReadyInfoViewController: BaseViewController { setupTextField(textField: rootView.readyMinuteTextField) setupTextField(textField: rootView.moveHourTextField) setupTextField(textField: rootView.moveMinuteTextField) + + let tapGesture = UITapGestureRecognizer() + view.addGestureRecognizer(tapGesture) + tapGesture.rx.event + .subscribe(with: self) { owner, _ in + owner.view.endEditing(true) + } + .disposed(by: disposeBag) } private func bindViewModel() { @@ -170,19 +177,6 @@ final class SetReadyInfoViewController: BaseViewController { textField.accessibilityIdentifier = identifier } } - - - // MARK: - Keyboard Dismissal - - private func setupTapGesture() { - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) - view.addGestureRecognizer(tapGesture) - } - - @objc - private func dismissKeyboard() { - view.endEditing(true) - } }