From ed4e6e31299c142102c09f3f055676a04bccc648 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 13 Sep 2024 22:40:43 +0900 Subject: [PATCH 01/28] =?UTF-8?q?fix/#382=20=EC=95=BD=EC=86=8D=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=EC=9E=90=20=EC=95=84=EB=8B=90=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=A4=80=EB=B9=84=20=EC=8B=9C=EC=9E=91=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EB=88=8C=EB=A0=80=EC=9D=84=20=EB=95=8C=20API=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=95=88=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyStatus/ViewController/ReadyStatusViewController.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index 65661298..8457d9a3 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -103,6 +103,9 @@ extension ReadyStatusViewController { owner.rootView.readyPlanInfoView.editButton.isHidden = flag owner.rootView.enterReadyButtonView.isUserInteractionEnabled = !flag && isParticipant + owner.rootView.myReadyStatusProgressView.readyStartButton.isUserInteractionEnabled = isParticipant + owner.rootView.myReadyStatusProgressView.moveStartButton.isUserInteractionEnabled = isParticipant + owner.rootView.myReadyStatusProgressView.arrivalButton.isUserInteractionEnabled = isParticipant } viewModel.promiseInfo.bindOnMain(with: self) { owner, model in From 4c0b042edda6b3c8f825cb1e3eff4da7ef0862a8 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 20:30:56 +0900 Subject: [PATCH 02/28] =?UTF-8?q?delete/#388=20=EC=95=BD=EC=86=8D=20?= =?UTF-8?q?=EC=83=81=EC=84=B8,=20=EC=95=BD=EC=86=8D=20=EC=A0=95=EB=B3=B4,?= =?UTF-8?q?=20=EC=A7=80=EA=B0=81=20=EA=BE=B8=EB=AC=BC=EC=9D=B4,=20?= =?UTF-8?q?=EC=A4=80=EB=B9=84=20=ED=98=84=ED=99=A9=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=AA=A8=EB=91=90=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseViewController.swift | 231 ++++---- .../PromiseInfoViewController.swift | 191 ++----- .../ReadyStatusViewController.swift | 497 ++---------------- .../ViewController/TardyViewController.swift | 89 ++-- .../Promise/ViewModel/PromiseViewModel.swift | 283 +++------- 5 files changed, 320 insertions(+), 971 deletions(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 4d53e4ee..389a31d1 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -16,29 +16,47 @@ class PromiseViewController: BaseViewController { private let promiseInfoViewController: PromiseInfoViewController private let promiseReadyStatusViewController: ReadyStatusViewController private let promiseTardyViewController: TardyViewController - private let exitViewController = CustomActionSheetController(kind: .exitPromise) - private let deleteViewController = CustomActionSheetController(kind: .deletePromise) + private let exitViewController = CustomActionSheetController( + kind: .exitPromise + ) + private let deleteViewController = CustomActionSheetController( + kind: .deletePromise + ) private let promisePageViewController = UIPageViewController( transitionStyle: .scroll, navigationOrientation: .vertical ) - private var removePromiseViewContoller: RemovePromiseViewController = RemovePromiseViewController(promiseName: "") + private var removePromiseViewContoller: RemovePromiseViewController = RemovePromiseViewController( + promiseName: "" + ) private var promiseViewControllerList: [BaseViewController] = [] private lazy var promiseSegmentedControl = PagePromiseSegmentedControl( - items: ["약속 정보", "준비 현황", "지각 꾸물이"] + items: [ + "약속 정보", + "준비 현황", + "지각 꾸물이" + ] ) // MARK: - LifeCycle - init(viewModel: PromiseViewModel) { + init( + viewModel: PromiseViewModel + ) { self.viewModel = viewModel - promiseInfoViewController = PromiseInfoViewController(viewModel: viewModel) - promiseReadyStatusViewController = ReadyStatusViewController(viewModel: viewModel) - promiseTardyViewController = TardyViewController(viewModel: viewModel) + promiseInfoViewController = PromiseInfoViewController( + viewModel: viewModel + ) + promiseReadyStatusViewController = ReadyStatusViewController( + viewModel: viewModel + ) + promiseTardyViewController = TardyViewController( + viewModel: viewModel + ) promiseViewControllerList = [ promiseInfoViewController, @@ -46,40 +64,56 @@ class PromiseViewController: BaseViewController { promiseTardyViewController ] - super.init(nibName: nil, bundle: nil) + super.init( + nibName: nil, + bundle: nil + ) } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + required init?( + coder: NSCoder + ) { + fatalError( + "init(coder:) has not been implemented" + ) } override func viewDidLoad() { super.viewDidLoad() setupNavigationBarBackButton() - setupPromiseEditButton(isHidden: false) setupBindings() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) + override func viewWillAppear( + _ animated: Bool + ) { + super.viewWillAppear( + animated + ) navigationController?.isNavigationBarHidden = false } - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) + override func viewWillDisappear( + _ animated: Bool + ) { + super.viewWillDisappear( + animated + ) navigationController?.isNavigationBarHidden = true } // MARK: - Setup - + override func setupView() { view.backgroundColor = .white - addChild(promisePageViewController) + addChild( + promisePageViewController + ) view.addSubviews( promiseSegmentedControl, @@ -93,13 +127,23 @@ class PromiseViewController: BaseViewController { ) promiseSegmentedControl.snp.makeConstraints { - $0.top.equalTo(view.safeAreaLayoutGuide) - $0.leading.trailing.equalToSuperview().inset(-6) - $0.height.equalTo(60) + $0.top.equalTo( + view.safeAreaLayoutGuide + ) + $0.leading.trailing.equalToSuperview().inset( + -6 + ) + $0.height.equalTo( + Screen.height( + 60 + ) + ) } promisePageViewController.view.snp.makeConstraints { - $0.top.equalTo(promiseSegmentedControl.snp.bottom) + $0.top.equalTo( + promiseSegmentedControl.snp.bottom + ) $0.leading.trailing.bottom.equalToSuperview() } } @@ -107,31 +151,41 @@ class PromiseViewController: BaseViewController { override func setupAction() { promiseSegmentedControl.addTarget( self, - action: #selector(didSegmentedControlIndexUpdated), + action: #selector( + didSegmentedControlIndexUpdated + ), for: .valueChanged ) promiseTardyViewController.tardyView.finishMeetingButton.addTarget( self, - action: #selector(finishMeetingButtonDidTap), + action: #selector( + finishMeetingButtonDidTap + ), for: .touchUpInside ) promiseTardyViewController.arriveView.finishMeetingButton.addTarget( self, - action: #selector(finishMeetingButtonDidTap), + action: #selector( + finishMeetingButtonDidTap + ), for: .touchUpInside ) removePromiseViewContoller.exitButton.addTarget( self, - action: #selector(exitButtonDidTap), + action: #selector( + exitButtonDidTap + ), for: .touchUpInside ) removePromiseViewContoller.deleteButton.addTarget( self, - action: #selector(deleteButtonDidTap), + action: #selector( + deleteButtonDidTap + ), for: .touchUpInside ) } @@ -148,87 +202,72 @@ class PromiseViewController: BaseViewController { private extension PromiseViewController { func setupBindings() { - viewModel.promiseInfo.bindOnMain(with: self) { owner, info in - owner.setupNavigationBarTitle(with: info?.promiseName ?? "", isBorderHidden: true) - owner.promiseInfoViewController.setupContent() - owner.promiseInfoViewController.setUpTimeContent() - owner.removePromiseViewContoller.promiseNameLabel.text = info?.promiseName ?? "" - - guard let isParticipant = info?.isParticipant else { return } - - owner.setupPromiseEditButton(isHidden: !isParticipant) - owner.promiseInfoViewController.rootView.editButton.isHidden = !isParticipant - } - } - - func setupPromiseEditButton(isHidden: Bool) { - let moreButton = UIBarButtonItem( - image: .imgMore.withRenderingMode(.alwaysOriginal), - style: .plain, - target: self, - action: #selector(self.moreButtonDidTap) - ) - - navigationItem.rightBarButtonItem = isHidden ? nil : moreButton + } @objc func didSegmentedControlIndexUpdated() { - let condition = viewModel.currentPageIndex.value <= promiseSegmentedControl.selectedSegmentIndex - let direction: UIPageViewController.NavigationDirection = condition ? .forward : .reverse - let (width, count, selectedIndex) = ( - promiseSegmentedControl.bounds.width, - promiseSegmentedControl.numberOfSegments, - promiseSegmentedControl.selectedSegmentIndex - ) - - promiseSegmentedControl.selectedUnderLineView.snp.updateConstraints { - $0.leading.equalToSuperview().offset((width / CGFloat(count)) * CGFloat(selectedIndex)) - } - - viewModel.segmentIndexDidChange( - index: promiseSegmentedControl.selectedSegmentIndex - ) - - promisePageViewController.setViewControllers([ - promiseViewControllerList[viewModel.currentPageIndex.value] - ], direction: direction, animated: false) + // let condition = viewModel.currentPageIndex.value <= promiseSegmentedControl.selectedSegmentIndex + // let direction: UIPageViewController.NavigationDirection = condition ? .forward : .reverse + // let (width, count, selectedIndex) = ( + // promiseSegmentedControl.bounds.width, + // promiseSegmentedControl.numberOfSegments, + // promiseSegmentedControl.selectedSegmentIndex + // ) + // + // promiseSegmentedControl.selectedUnderLineView.snp.updateConstraints { + // $0.leading.equalToSuperview().offset((width / CGFloat(count)) * CGFloat(selectedIndex)) + // } + // + // viewModel.segmentIndexDidChange( + // index: promiseSegmentedControl.selectedSegmentIndex + // ) + // + // promisePageViewController.setViewControllers([ + // promiseViewControllerList[viewModel.currentPageIndex.value] + // ], direction: direction, animated: false) } @objc func finishMeetingButtonDidTap() { - promiseTardyViewController.viewModel.updatePromiseCompletion { - DispatchQueue.main.async { - self.navigationController?.popViewController(animated: true) - - if let viewController = self.navigationController?.viewControllers.last { - let toast = Toast() - toast.show(message: "약속 마치기 성공!", view: viewController.view, position: .bottom, inset: 100) - } - } - } + } @objc func moreButtonDidTap() { let bottomSheetViewController = BottomSheetViewController( contentViewController: removePromiseViewContoller, - defaultHeight: Screen.height(232) + defaultHeight: Screen.height( + 232 + ) ) - present(bottomSheetViewController, animated: true) + present( + bottomSheetViewController, + animated: true + ) } @objc func exitButtonDidTap() { - dismiss(animated: false) - present(exitViewController, animated: true) + dismiss( + animated: false + ) + present( + exitViewController, + animated: true + ) } @objc func deleteButtonDidTap() { - dismiss(animated: false) - present(deleteViewController, animated: true) + dismiss( + animated: false + ) + present( + deleteViewController, + animated: true + ) } } @@ -236,24 +275,18 @@ private extension PromiseViewController { // MARK: - CustomActionSheetDelegate extension PromiseViewController: CustomActionSheetDelegate { - func actionButtonDidTap(for kind: ActionSheetKind) { + func actionButtonDidTap( + for kind: ActionSheetKind + ) { if kind == .deletePromise { - dismiss(animated: false) - - viewModel.deletePromise() { - DispatchQueue.main.async { - self.navigationController?.popViewController(animated: true) - } - } + dismiss( + animated: false + ) } else { - dismiss(animated: false) - - viewModel.exitPromise() { - DispatchQueue.main.async { - self.navigationController?.popViewController(animated: true) - } - } + dismiss( + animated: false + ) } } } diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 44da0ec1..93a8926e 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -20,14 +20,23 @@ class PromiseInfoViewController: BaseViewController { // MARK: - LifeCycle - init(viewModel: PromiseViewModel) { + init( + viewModel: PromiseViewModel + ) { self.viewModel = viewModel - super.init(nibName: nil, bundle: nil) + super.init( + nibName: nil, + bundle: nil + ) } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + required init?( + coder: NSCoder + ) { + fatalError( + "init(coder:) has not been implemented" + ) } override func loadView() { @@ -40,12 +49,12 @@ class PromiseInfoViewController: BaseViewController { setupBinding() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - viewModel.fetchPromiseParticipantList() - viewModel.fetchPromiseInfo() - viewModel.fetchTardyInfo() + override func viewWillAppear( + _ animated: Bool + ) { + super.viewWillAppear( + animated + ) } @@ -61,7 +70,13 @@ class PromiseInfoViewController: BaseViewController { } override func setupAction() { - rootView.editButton.addTarget(self, action: #selector(editButtonDidTap), for: .touchUpInside) + rootView.editButton.addTarget( + self, + action: #selector( + editButtonDidTap + ), + for: .touchUpInside + ) } } @@ -71,123 +86,11 @@ class PromiseInfoViewController: BaseViewController { extension PromiseInfoViewController { @objc func editButtonDidTap() { - if var dressUpLevel = viewModel.promiseInfo.value?.dressUpLevel { - let levels = ["LV1", "LV2", "LV3", "LV4", "FREE"] - - if dressUpLevel.contains("마음대로 입고 오기") { - dressUpLevel = "FREE" - } - else { - if let matched = levels.first(where: { - level in dressUpLevel.replacingOccurrences(of: " ", with: "").contains(level) - }) { - dressUpLevel = matched - } - } - - let viewController = EditPromiseViewController( - viewModel: EditPromiseViewModel( - promiseID: viewModel.promiseID, - promiseName: viewModel.promiseInfo.value?.promiseName, - placeName: viewModel.promiseInfo.value?.placeName, - xCoordinate: viewModel.promiseInfo.value?.x, - yCoordinate: viewModel.promiseInfo.value?.y, - address: viewModel.promiseInfo.value?.address, - roadAddress: viewModel.promiseInfo.value?.roadAddress, - time: viewModel.promiseInfo.value?.time, - dressUpLevel: dressUpLevel, - penalty: viewModel.promiseInfo.value?.penalty, - service: PromiseService() - ) - ) - - navigationController?.pushViewController(viewController, animated: true) - } - } - - func setupBinding() { - viewModel.isPastDue.bindOnMain(with: self) { owner, isPastDue in - owner.rootView.editButton.isHidden = isPastDue - } - viewModel.participantsInfo.bindOnMain(with: self) { owner, participantsInfo in - owner.rootView.participantNumberLabel.setText( - "약속 참여 인원 \(participantsInfo?.count ?? 0)명", - style: .body05, - color: .maincolor - ) - - owner.rootView.participantNumberLabel.setHighlightText( - "\(participantsInfo?.count ?? 0)명", - style: .body05, - color: .gray3 - ) - - self.rootView.participantCollectionView.layoutIfNeeded() - owner.rootView.participantCollectionView.reloadData() - } } - func setupContent() { - self.rootView.promiseNameLabel.setText( - self.viewModel.promiseInfo.value?.promiseName ?? "", - style: .body01 - ) + func setupBinding() { - self.rootView.locationContentLabel.setText( - self.viewModel.promiseInfo.value?.placeName ?? "약속 장소 미설정", - style: .body04 - ) - self.rootView.readyLevelContentLabel.setText( - self.viewModel.promiseInfo.value?.dressUpLevel ?? "꾸레벨 미설정", - style: .body04 - ) - self.rootView.penaltyLevelContentLabel.setText( - self.viewModel.promiseInfo.value?.penalty ?? "벌칙 미설정", - style: .body04 - ) - } - - func setUpTimeContent() { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" - dateFormatter.locale = Locale(identifier: "ko_KR") - dateFormatter.timeZone = TimeZone(identifier: "Asia/Seoul") - - guard let dateWithTime = dateFormatter.date(from: viewModel.promiseInfo.value?.time ?? "") else { - return - } - - let calendar = Calendar.current - - let dateOnly = calendar.startOfDay(for: dateWithTime) - let today = calendar.startOfDay(for: Date()) - - let components = calendar.dateComponents([.day], from: today, to: dateOnly) - guard let remainDay = components.day else { - return - } - - if remainDay == 0 { - rootView.dDayLabel.setText("D-DAY", style: .body05, color: .mainorange) - rootView.promiseImageView.image = .imgPromise - rootView.promiseNameLabel.textColor = .gray7 - } else if remainDay < 0 { - rootView.dDayLabel.setText("D+\(-remainDay)", style: .body05, color: .gray4) - rootView.promiseImageView.image = .imgPromiseGray - rootView.promiseNameLabel.textColor = .gray4 - } else { - rootView.dDayLabel.setText("D-\(remainDay)", style: .body05, color: .gray5) - rootView.promiseImageView.image = .imgPromise - rootView.promiseNameLabel.textColor = .gray7 - } - - dateFormatter.dateFormat = "M월 d일 a h:mm" - dateFormatter.amSymbol = "AM" - dateFormatter.pmSymbol = "PM" - let time = dateFormatter.string(from: dateWithTime) - - rootView.timeContentLabel.setText(time, style: .body04) } } @@ -199,11 +102,7 @@ extension PromiseInfoViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - guard let info = viewModel.participantsInfo.value else { - return 0 - } - - return info.count + return 0 } func collectionView( @@ -212,22 +111,11 @@ extension PromiseInfoViewController: UICollectionViewDataSource { ) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell( withReuseIdentifier: ParticipantCollectionViewCell.reuseIdentifier, - for: indexPath) as? ParticipantCollectionViewCell - else { return UICollectionViewCell() } - - guard let info = viewModel.participantsInfo.value?[indexPath.row] else { - return cell - } - - cell.userNameLabel.setText(info.name, style: .caption02, color: .gray6) - - guard let image = URL(string: info.profileImageURL ?? "") else { - cell.profileImageView.image = .imgProfile - - return cell + for: indexPath + ) as? ParticipantCollectionViewCell + else { + return UICollectionViewCell() } - - cell.profileImageView.kf.setImage(with: image) return cell } @@ -237,8 +125,19 @@ extension PromiseInfoViewController: UICollectionViewDataSource { // MARK: - UICollectionViewDelegateFlowLayout extension PromiseInfoViewController: UICollectionViewDelegateFlowLayout { - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - return CGSize(width: Screen.width(68), height: Screen.height(88)) + func collectionView( + _ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath + ) -> CGSize { + return CGSize( + width: Screen.width( + 68 + ), + height: Screen.height( + 88 + ) + ) } } diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index 8457d9a3..d2451fc5 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -20,14 +20,23 @@ class ReadyStatusViewController: BaseViewController { // MARK: - LifeCycle - init(viewModel: PromiseViewModel) { + init( + viewModel: PromiseViewModel + ) { self.viewModel = viewModel - super.init(nibName: nil, bundle: nil) + super.init( + nibName: nil, + bundle: nil + ) } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + required init?( + coder: NSCoder + ) { + fatalError( + "init(coder:) has not been implemented" + ) } override func loadView() { @@ -42,13 +51,12 @@ class ReadyStatusViewController: BaseViewController { setupBinding() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - viewModel.fetchTardyInfo() - viewModel.fetchPromiseInfo() - viewModel.fetchMyReadyStatus() - viewModel.fetchPromiseParticipantList() + override func viewWillAppear( + _ animated: Bool + ) { + super.viewWillAppear( + animated + ) } override func viewDidLayoutSubviews() { @@ -66,28 +74,38 @@ class ReadyStatusViewController: BaseViewController { override func setupAction() { rootView.myReadyStatusProgressView.readyStartButton.addTarget( self, - action: #selector(readyStartButtonDidTap), + action: #selector( + readyStartButtonDidTap + ), for: .touchUpInside ) rootView.myReadyStatusProgressView.moveStartButton.addTarget( self, - action: #selector(moveStartButtonDidTap), + action: #selector( + moveStartButtonDidTap + ), for: .touchUpInside ) rootView.myReadyStatusProgressView.arrivalButton.addTarget( self, - action: #selector(arrivalButtonDidTap), + action: #selector( + arrivalButtonDidTap + ), for: .touchUpInside ) rootView.readyPlanInfoView.editButton.addTarget( self, - action: #selector(editReadyButtonDidTap), + action: #selector( + editReadyButtonDidTap + ), for: .touchUpInside ) rootView.enterReadyButtonView.addGestureRecognizer( UITapGestureRecognizer( target: self, - action: #selector(enterReadyButtonDidTap) + action: #selector( + enterReadyButtonDidTap + ) ) ) } @@ -98,444 +116,32 @@ class ReadyStatusViewController: BaseViewController { extension ReadyStatusViewController { func setupBinding() { - viewModel.isPastDue.bindOnMain(with: self) { owner, flag in - guard let isParticipant = owner.viewModel.promiseInfo.value?.isParticipant else { return } - - owner.rootView.readyPlanInfoView.editButton.isHidden = flag - owner.rootView.enterReadyButtonView.isUserInteractionEnabled = !flag && isParticipant - owner.rootView.myReadyStatusProgressView.readyStartButton.isUserInteractionEnabled = isParticipant - owner.rootView.myReadyStatusProgressView.moveStartButton.isUserInteractionEnabled = isParticipant - owner.rootView.myReadyStatusProgressView.arrivalButton.isUserInteractionEnabled = isParticipant - } - - viewModel.promiseInfo.bindOnMain(with: self) { owner, model in - guard let isParticipant = model?.isParticipant else { return } - - if !isParticipant { - owner.updateReadyInfoView(flag: false) - owner.rootView.myReadyStatusProgressView.readyStartButton.setupButton("준비 시작", .none) - } - } - - viewModel.myReadyStatus.bindOnMain(with: self) { owner, model in - guard let status = model else { return } - - /// 준비 시간을 계산해 UI에 표시 - owner.viewModel.calculateDuration() - owner.viewModel.calculateStartTime() - - /// myReadyStatus의 바인딩 부분에 조건을 통해 myReadyProgressStatus 값을 업데이트 - if status.preparationStartAt == nil { - owner.viewModel.myReadyProgressStatus.value = .none - } - else if status.departureAt == nil { - owner.viewModel.myReadyProgressStatus.value = .ready - } - else if status.arrivalAt == nil { - owner.viewModel.myReadyProgressStatus.value = .move - } - else { - owner.viewModel.myReadyProgressStatus.value = .done - } - - /// 준비하기 버튼과 준비 정보 화면 중 어떤 걸 표시할지 결정 - if status.preparationTime == nil { - owner.updateReadyInfoView(flag: false) - return - } - - owner.updateReadyInfoView(flag: true) - owner.updateLatePopupStatus() - } - - viewModel.myReadyProgressStatus.bindOnMain(with: self) { owner, status in - owner.updateLatePopupStatus() - } - - viewModel.moveDuration.bind(with: self) { owner, moveTime in - owner.rootView.readyPlanInfoView.requestMoveTimeLabel.setText( - "이동 소요 시간: \(moveTime)", - style: .label02, - color: .gray8 - ) - } - - viewModel.readyDuration.bind(with: self) { - owner, - readyTime in - owner.rootView.readyPlanInfoView.requestReadyTimeLabel.setText( - "준비 소요 시간: \(readyTime)", - style: .label02, - color: .gray8 - ) - } - - viewModel.readyStartTime.bind(with: self) { - owner, - readyStartTime in - DispatchQueue.main.async { - owner.rootView.readyPlanInfoView.readyTimeLabel.setText( - "\(readyStartTime)에 준비하고,\n\(owner.viewModel.moveStartTime.value)에 이동을 시작해야 해요", - style: .body03 - ) - - owner.rootView.readyPlanInfoView.readyTimeLabel.setHighlightText( - for: [readyStartTime, owner.viewModel.moveStartTime.value], - style: .body03, - color: .maincolor - ) - } - } - - viewModel.moveStartTime.bind(with: self) { owner, moveStartTime in - DispatchQueue.main.async { - owner.rootView.readyPlanInfoView.readyTimeLabel.setText( - "\(owner.viewModel.readyStartTime.value)에 준비하고,\n\(moveStartTime)에 이동을 시작해야 해요", - style: .body03 - ) - - owner.rootView.readyPlanInfoView.readyTimeLabel.setHighlightText( - for: [owner.viewModel.readyStartTime.value, moveStartTime], - style: .body03, - color: .maincolor - ) - } - } - - viewModel.myReadyProgressStatus.bindOnMain(with: self) { owner, status in - owner.updateReadyStartButton() - owner.updateLatePopupStatus() - owner.rootView.ourReadyStatusCollectionView.reloadData() - } - - viewModel.participantsInfo.bindOnMain(with: self) { owner, participants in - owner.rootView.ourReadyStatusCollectionView.reloadData() - - owner.rootView.ourReadyStatusCollectionView.snp.updateConstraints { - $0.height.equalTo( - CGFloat(participants?.count ?? 0) * Screen.height(80) - ) - } - } - } - - func updateLatePopupStatus() { - let date = Calendar.current - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "HH시 mm분" - dateFormatter.locale = Locale(identifier: "ko_KR") - dateFormatter.timeZone = TimeZone(identifier: "Asia/Seoul") - - guard let readyStartTime = dateFormatter.date(from: viewModel.readyStartTime.value) else { return } - guard let moveStartTime = dateFormatter.date(from: viewModel.moveStartTime.value) else { return } - - let readyStartComponent = date.dateComponents([.hour, .minute], from: readyStartTime) - let moveStartComponents = date.dateComponents([.hour, .minute], from: moveStartTime) - let currentTimeComponents = date.dateComponents([.hour, .minute], from: Date()) - - guard let readyStartHour = readyStartComponent.hour, - let readyStartMinute = readyStartComponent.minute, - let moveStartHour = moveStartComponents.hour, - let moveStartMinute = moveStartComponents.minute, - let currentTimeHour = currentTimeComponents.hour, - let currentTimeMinute = currentTimeComponents.minute else { return } - - DispatchQueue.main.async { - if (currentTimeHour >= readyStartHour) && (currentTimeMinute > readyStartMinute) && ((currentTimeHour <= moveStartHour) && (currentTimeMinute < moveStartMinute)) { - let readyLateFlag = !(self.viewModel.myReadyProgressStatus.value == .none) - - print(">> \(readyLateFlag) : \(#function)") - - self.rootView.popUpImageView.isHidden = readyLateFlag - } - else if ((currentTimeHour >= moveStartHour) && (currentTimeMinute > moveStartMinute)) && self.viewModel.isPastDue.value == false { - let moveLateFlag = !(self.viewModel.myReadyProgressStatus.value == .none || self.viewModel.myReadyProgressStatus.value == .ready) - - print(">>> \(moveLateFlag) : \(#function)") - - self.rootView.popUpImageView.isHidden = moveLateFlag - } - else { - let arriveLateFlag = self.viewModel.isPastDue.value && !(self.viewModel.myReadyProgressStatus.value == .done) - - print(">>>> \(arriveLateFlag) : \(#function)") - - self.rootView.popUpImageView.isHidden = arriveLateFlag - } - } - } - - /// flag에 따라 준비 정보 입력 버튼 표시 유무 변경 - func updateReadyInfoView(flag: Bool) { - rootView.enterReadyButtonView.isHidden = flag - rootView.readyPlanInfoView.isHidden = !flag - } - - /// 준비 시작이나 이동 시작 시간이 늦었을 때 팝업 표시 여부 변경 - func updatePopUpImageView() { - rootView.popUpImageView.isHidden = !viewModel.isLate.value - rootView.readyBaseView.layoutIfNeeded() - } - - /// 준비 상태에 따라 버튼 상태 변경 - func updateReadyStartButton() { - switch viewModel.myReadyProgressStatus.value { - case .none: - DispatchQueue.main.async { - self.rootView.myReadyStatusProgressView.readyStartButton.setupButton( - "준비 시작", - .ready - ) - self.rootView.myReadyStatusProgressView.moveStartButton.setupButton( - "이동 시작", - .none - ) - self.rootView.myReadyStatusProgressView.arrivalButton.setupButton( - "도착 완료", - .none - ) - self.rootView.myReadyStatusProgressView.statusProgressView.setProgress(0, animated: false) - } - case .ready: - DispatchQueue.main.async { - self.rootView.myReadyStatusProgressView.readyStartButton.setupButton( - "준비 중", - .move - ) - self.rootView.myReadyStatusProgressView.moveStartButton.setupButton( - "이동 시작", - .ready - ) - self.rootView.myReadyStatusProgressView.arrivalButton.setupButton( - "도착 완료", - .none - ) - self.rootView.myReadyStatusProgressView.statusProgressView.setProgress(0.2, animated: false) - - self.rootView.myReadyStatusProgressView.readyStartButton.isEnabled = false - self.rootView.myReadyStatusProgressView.moveStartButton.isEnabled = true - - [ - self.rootView.myReadyStatusProgressView.moveStartTimeLabel, - self.rootView.myReadyStatusProgressView.readyStartTitleLabel - ].forEach { $0.isHidden = true } - - [ - self.rootView.myReadyStatusProgressView.readyStartTimeLabel, - self.rootView.myReadyStatusProgressView.moveStartTitleLabel - ].forEach { $0.isHidden = false } - - self.rootView.myReadyStatusProgressView.readyStartCheckImageView.backgroundColor = .green2 - - /// myReadyStatus의 preparationStartAt 값이 있으면 그 값으로 업데이트 - if let preparationStartAt = self.viewModel.myReadyStatus.value?.preparationStartAt { - self.rootView.myReadyStatusProgressView.readyStartTimeLabel.setText( - preparationStartAt, - style: .caption02, - color: .gray8 - ) - } - else { - self.rootView.myReadyStatusProgressView.readyStartTimeLabel.setText( - self.viewModel.updateReadyStatusTime(), - style: .caption02, - color: .gray8 - ) - } - } - case .move: - DispatchQueue.main.async { - self.rootView.myReadyStatusProgressView.readyStartButton.setupButton( - "준비 완료", - .done - ) - self.rootView.myReadyStatusProgressView.moveStartButton.setupButton( - "이동 중", - .move - ) - self.rootView.myReadyStatusProgressView.arrivalButton.setupButton( - "도착 완료", - .ready - ) - self.rootView.myReadyStatusProgressView.statusProgressView.setProgress( - 0.5, - animated: false - ) - - self.rootView.myReadyStatusProgressView.moveStartButton.isEnabled = false - self.rootView.myReadyStatusProgressView.arrivalButton.isEnabled = true - - self.rootView.myReadyStatusProgressView.arrivalTitleLabel.isHidden = false - self.rootView.myReadyStatusProgressView.moveStartTitleLabel.isHidden = true - self.rootView.myReadyStatusProgressView.readyStartTitleLabel.isHidden = true - self.rootView.myReadyStatusProgressView.arrivalTimeLabel.isHidden = true - self.rootView.myReadyStatusProgressView.moveStartTimeLabel.isHidden = false - self.rootView.myReadyStatusProgressView.readyStartTimeLabel.isHidden = false - - - self.rootView.myReadyStatusProgressView.readyStartCheckImageView.image = .iconCheck - self.rootView.myReadyStatusProgressView.moveStartCheckImageView.image = .iconCheck - - /// myReadyStatus의 arrivalAt 값이 있으면 그 값으로 업데이트 - if let preparationStartAt = self.viewModel.myReadyStatus.value?.preparationStartAt { - self.rootView.myReadyStatusProgressView.readyStartTimeLabel.setText( - preparationStartAt, - style: .caption02, - color: .gray8 - ) - } - if let departureAt = self.viewModel.myReadyStatus.value?.departureAt { - self.rootView.myReadyStatusProgressView.moveStartTimeLabel.setText( - departureAt, - style: .caption02, - color: .gray8 - ) - } - else { - self.rootView.myReadyStatusProgressView.moveStartTimeLabel.setText( - self.viewModel.updateReadyStatusTime(), - style: .caption02, - color: .gray8 - ) - } - } - case .done: - DispatchQueue.main.async { - self.rootView.myReadyStatusProgressView.readyStartButton.setupButton( - "준비 완료", - .done - ) - self.rootView.myReadyStatusProgressView.moveStartButton.setupButton( - "이동 완료", - .done - ) - self.rootView.myReadyStatusProgressView.arrivalButton.setupButton( - "도착 완료", - .done - ) - self.rootView.myReadyStatusProgressView.statusProgressView.setProgress( - 1, - animated: false - ) - - self.rootView.myReadyStatusProgressView.arrivalButton.isEnabled = false - - [ - self.rootView.myReadyStatusProgressView.arrivalTitleLabel, - self.rootView.myReadyStatusProgressView.moveStartTitleLabel, - self.rootView.myReadyStatusProgressView.readyStartTitleLabel - ].forEach { $0.isHidden = true } - - [ - self.rootView.myReadyStatusProgressView.arrivalTimeLabel, - self.rootView.myReadyStatusProgressView.moveStartTimeLabel, - self.rootView.myReadyStatusProgressView.readyStartTimeLabel - ].forEach { $0.isHidden = false } - - [ - self.rootView.myReadyStatusProgressView.readyStartCheckImageView, - self.rootView.myReadyStatusProgressView.moveStartCheckImageView, - self.rootView.myReadyStatusProgressView.arrivalCheckImageView - ].forEach { $0.image = .iconCheck } - - /// myReadyStatus의 arrivalAt 값이 있으면 그 값으로 업데이트 - if let preparationStartAt = self.viewModel.myReadyStatus.value?.preparationStartAt { - self.rootView.myReadyStatusProgressView.readyStartTimeLabel.setText( - preparationStartAt, - style: .caption02, - color: .gray8 - ) - } - if let departureAt = self.viewModel.myReadyStatus.value?.departureAt { - self.rootView.myReadyStatusProgressView.moveStartTimeLabel.setText( - departureAt, - style: .caption02, - color: .gray8 - ) - } - if let arrivalAt = self.viewModel.myReadyStatus.value?.arrivalAt { - self.rootView.myReadyStatusProgressView.arrivalTimeLabel.setText( - arrivalAt, - style: .caption02, - color: .gray8 - ) - } - else { - self.rootView.myReadyStatusProgressView.arrivalTimeLabel.setText( - self.viewModel.updateReadyStatusTime(), - style: .caption02, - color: .gray8 - ) - } - } - } } @objc func readyStartButtonDidTap() { - viewModel.updatePreparationStatus { [weak self] in - self?.viewModel.fetchPromiseParticipantList() - } + } @objc func moveStartButtonDidTap() { - viewModel.updateDepartureStatus { [weak self] in - self?.viewModel.fetchPromiseParticipantList() - } + } @objc func arrivalButtonDidTap() { - viewModel.updateArrivalStatus { [weak self] in - self?.viewModel.fetchPromiseParticipantList() - } + } @objc func editReadyButtonDidTap() { - guard let _ = viewModel.promiseInfo.value?.promiseName else { return } - guard let readyStatusInfo = viewModel.myReadyStatus.value else { return } - - let setReadyInfoViewModel = SetReadyInfoViewModel( - promiseID: viewModel.promiseID, - promiseTime: readyStatusInfo.promiseTime, - promiseName: viewModel.promiseInfo.value?.promiseName ?? "", - service: PromiseService() - ) - - setReadyInfoViewModel.storedReadyHour = (readyStatusInfo.preparationTime ?? 0) / 60 - setReadyInfoViewModel.storedReadyMinute = (readyStatusInfo.preparationTime ?? 0) % 60 - setReadyInfoViewModel.storedMoveHour = (readyStatusInfo.travelTime ?? 0) / 60 - setReadyInfoViewModel.storedMoveMinute = (readyStatusInfo.travelTime ?? 0) % 60 - - let setReadyInfoViewController = SetReadyInfoViewController(viewModel: setReadyInfoViewModel) - navigationController?.pushViewController( - setReadyInfoViewController, - animated: true - ) } @objc func enterReadyButtonDidTap() { - guard let _ = viewModel.promiseInfo.value?.promiseName else { return } - guard let readyStatusInfo = viewModel.myReadyStatus.value else { return } - let setReadyInfoViewController = SetReadyInfoViewController( - viewModel: SetReadyInfoViewModel( - promiseID: viewModel.promiseID, - promiseTime: readyStatusInfo.promiseTime, - promiseName: viewModel.promiseInfo.value?.promiseName ?? "", - service: PromiseService() - ) - ) - - navigationController?.pushViewController( - setReadyInfoViewController, - animated: true - ) } } @@ -547,7 +153,7 @@ extension ReadyStatusViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - return viewModel.participantsInfo.value?.count ?? 0 + return 0 } func collectionView( @@ -558,31 +164,8 @@ extension ReadyStatusViewController: UICollectionViewDataSource { withReuseIdentifier: OurReadyStatusCollectionViewCell.reuseIdentifier, for: indexPath ) as? OurReadyStatusCollectionViewCell - else { return UICollectionViewCell() } - - cell.nameLabel.setText( - viewModel.participantsInfo.value?[indexPath.row].name ?? "", - style: .body03, - color: .gray8 - ) - - if let imageURL = URL(string: viewModel.participantsInfo.value?[indexPath.row].profileImageURL ?? "") { - cell.profileImageView.kf.setImage(with: imageURL, placeholder: UIImage.imgProfile) - } - - switch viewModel.participantsInfo.value?[indexPath.row].state { - case "꾸물중": - cell.readyStatusButton.setupButton("꾸물중", .none) - case "준비중": - cell.readyStatusButton.setupButton("준비중", .ready) - case "이동중": - cell.readyStatusButton.setupButton("이동중", .move) - case "도착": - cell.readyStatusButton.setupButton("도착", .done) - case .none: - return cell - case .some(_): - return cell + else { + return UICollectionViewCell() } return cell diff --git a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift index 653212a1..4df2a9bb 100644 --- a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift +++ b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift @@ -19,14 +19,23 @@ class TardyViewController: BaseViewController { // MARK: - LifeCycle - init(viewModel: PromiseViewModel) { + init( + viewModel: PromiseViewModel + ) { self.viewModel = viewModel - super.init(nibName: nil, bundle: nil) + super.init( + nibName: nil, + bundle: nil + ) } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + required init?( + coder: NSCoder + ) { + fatalError( + "init(coder:) has not been implemented" + ) } override func viewDidLoad() { @@ -35,8 +44,12 @@ class TardyViewController: BaseViewController { setupBinding() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) + override func viewWillAppear( + _ animated: Bool + ) { + super.viewWillAppear( + animated + ) viewModel.fetchTardyInfo() } @@ -45,9 +58,15 @@ class TardyViewController: BaseViewController { // MARK: - Setup override func setupView() { - view.addSubviews(arriveView, tardyView) + view.addSubviews( + arriveView, + tardyView + ) - [arriveView, tardyView].forEach { + [ + arriveView, + tardyView + ].forEach { $0.snp.makeConstraints { $0.edges.equalToSuperview() } @@ -64,44 +83,7 @@ class TardyViewController: BaseViewController { private extension TardyViewController { func setupBinding() { - /// 시간이 지나고 지각자가 없을 때 arriveView로 띄워짐 - viewModel.isPastDue.bindOnMain(with: self) { owner, isPastDue in - owner.tardyView.finishMeetingButton.isEnabled = (isPastDue && (owner.viewModel.promiseInfo.value?.isParticipant ?? false)) - } - - viewModel.penalty.bindOnMain(with: self) { owner, penalty in - owner.tardyView.tardyPenaltyView.contentLabel.setText( - penalty, - style: .body03, - color: .gray8 - ) - } - - viewModel.hasTardy.bindOnMain(with: self) { owner, hasTardy in - let isPastDue = owner.viewModel.isPastDue.value - let arriveHideFlag = !(isPastDue && !hasTardy) - - owner.arriveView.isHidden = arriveHideFlag - owner.tardyView.isHidden = !arriveHideFlag - owner.tardyView.tardyCollectionView.isHidden = !isPastDue - owner.tardyView.tardyEmptyView.isHidden = isPastDue - } - viewModel.comers.bind(with: self) { owner, comers in - DispatchQueue.main.async { - owner.tardyView.tardyCollectionView.reloadData() - } - } - - viewModel.errorMessage.bindOnMain(with: self) { owner, error in - let toast = Toast() - toast.show( - message: error, - view: owner.view, - position: .bottom, - inset: 100 - ) - } } } @@ -112,7 +94,7 @@ extension TardyViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - return viewModel.comers.value.count + return 0 } func collectionView( @@ -122,18 +104,9 @@ extension TardyViewController: UICollectionViewDataSource { guard let cell = collectionView.dequeueReusableCell( withReuseIdentifier: TardyCollectionViewCell.reuseIdentifier, for: indexPath - ) as? TardyCollectionViewCell else { return UICollectionViewCell() } - - cell.nameLabel.setText( - viewModel.comers.value[indexPath.row].name ?? "", - style: .body06, - color: .gray6 - ) - - cell.profileImageView.kf.setImage( - with: URL(string: viewModel.comers.value[indexPath.row].profileImageURL ?? ""), - placeholder: UIImage.imgProfile - ) + ) as? TardyCollectionViewCell else { + return UICollectionViewCell() + } return cell } diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 01e824e8..4e2fd9a4 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -7,11 +7,6 @@ import Foundation -enum TappedButton { - case ready - case move -} - class PromiseViewModel { @@ -20,66 +15,15 @@ class PromiseViewModel { /// 서버 통신을 위해 생성자로 주입받을 약속 ID let promiseID: Int - /// 현재 페이지 인덱스 - let currentPageIndex = ObservablePattern(0) - - /// 약속 정보 - let promiseInfo = ObservablePattern(nil) - - /// 우리들의 준비 현황 스택 뷰에 들어갈 정보들 - let participantsInfo = ObservablePattern<[Participant]?>(nil) - - /// 나의 준비현황이 담긴 정보 - /// 설령 데이터가 없다하더라도 약속 시간은 담겨있음. - let myReadyStatus = ObservablePattern(nil) - - /// 현재 준비 상태에 대한 버튼 처리 - let myReadyProgressStatus = ObservablePattern(.none) - - /// 준비 시작 시간 - var readyStartTime = ObservablePattern("") - - /// 준비 소요 시간 - var readyDuration = ObservablePattern("") - - /// 이동 시작 시간 - var moveStartTime = ObservablePattern("") - - /// 이동 소요 시간 - var moveDuration = ObservablePattern("") - - /// 꾸물거림 여부 - var isLate = ObservablePattern(false) - - /// 지각자 유무 여부 - var hasTardy: ObservablePattern = ObservablePattern(false) - - /// 약속 시간 지났는지 여부 - var isPastDue: ObservablePattern = ObservablePattern(false) - - /// 벌칙 정보 - var penalty: ObservablePattern = ObservablePattern("") - - /// 지각자 목록 - var comers: ObservablePattern<[Comer]> = ObservablePattern<[Comer]>([]) - - /// 서버로부터 받아올 에러 메시지 - var errorMessage: ObservablePattern = ObservablePattern("") - - /// 현재 시간 받아오기 위한 dateFormatter 구헌 - private let dateFormatter = DateFormatter().then { - $0.locale = Locale(identifier: "ko_KR") - $0.timeZone = TimeZone(identifier: "Asia/Seoul") - $0.amSymbol = "AM" - $0.pmSymbol = "PM" - } - private let service: PromiseServiceProtocol // MARK: Initialize - init(promiseID: Int, service: PromiseServiceProtocol) { + init( + promiseID: Int, + service: PromiseServiceProtocol + ) { self.service = service self.promiseID = promiseID } @@ -89,94 +33,23 @@ class PromiseViewModel { // MARK: - Extension extension PromiseViewModel { - /// segmentedControl 인덱스 바뀌었을 때 호출되는 함수 - func segmentIndexDidChange(index: Int) { - currentPageIndex.value = index - } - - /// 우리들의 준비 현황 변동되었을 때 호출되는 함수 - func participantInfosDidChanged(infos: [Participant]) { - participantsInfo.value = infos - } - - /// 준비 현황 버튼 클릭했을 때 현재 시간 반환하는 함수 - func updateReadyStatusTime() -> String { - dateFormatter.dateFormat = "a h:mm" - - return dateFormatter.string(from: Date()) - } - - func updateMyReadyProgressStatus() { - myReadyProgressStatus.value = myReadyStatus.value?.preparationStartAt == nil ? .none - : myReadyStatus.value?.departureAt == nil ? .ready - : myReadyStatus.value?.arrivalAt == nil ? .move - : .done - } - - /// 준비 or 이동 소요 시간 계산하는 함수 - func calculateDuration() { - let preparationHours = (self.myReadyStatus.value?.preparationTime ?? 0) / 60 - let preparationMinutes = (self.myReadyStatus.value?.preparationTime ?? 0) % 60 - - readyDuration.value = preparationHours == 0 ? "\(preparationMinutes)분" : "\(preparationHours)시간 \(preparationMinutes)분" - - let travelHours = (self.myReadyStatus.value?.travelTime ?? 0) / 60 - let travelMinutes = (self.myReadyStatus.value?.travelTime ?? 0) % 60 - - moveDuration.value = travelHours == 0 ? "\(travelMinutes)분" : "\(travelHours)시간 \(travelMinutes)분" - } - - /// 준비 or 이동 시작 시간 계산하는 함수 - func calculateStartTime() { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" - - let promiseTime = self.myReadyStatus.value?.promiseTime ?? "" - let readyTime = self.myReadyStatus.value?.preparationTime ?? 0 - let moveTime = self.myReadyStatus.value?.travelTime ?? 0 - - - guard let promiseDate = dateFormatter.date(from: promiseTime) else { - print("Invalid date format: \(promiseTime)") - return - } - - let totalPrepTime = TimeInterval((readyTime + moveTime) * 60) - - let timeFormatter = DateFormatter() - timeFormatter.dateFormat = "HH시 mm분" - timeFormatter.timeZone = TimeZone(identifier: "Asia/Seoul") - - print("약속 시간: \(timeFormatter.string(from: promiseDate))") - print("준비 시간: \(readyTime) 분") - print("이동 시간: \(moveTime) 분") - print("총 준비 시간: \(totalPrepTime / 60) 분") - - let readyStartTime = promiseDate.addingTimeInterval(-TimeInterval(readyTime + moveTime + 10) * 60) - let moveStartTime = promiseDate.addingTimeInterval(-TimeInterval(moveTime + 10) * 60) - - self.readyStartTime.value = timeFormatter.string(from: readyStartTime) - print("준비 시작 시간: \(self.readyStartTime.value)") - - self.moveStartTime.value = timeFormatter.string(from: moveStartTime) - print("이동 시작 시간: \(self.moveStartTime.value)") - } - /// 약속 상세 정보 조회 API 구현 함수 func fetchPromiseInfo() { Task { do { - let result = try await service.fetchPromiseInfo(with: promiseID) + let result = try await service.fetchPromiseInfo( + with: promiseID + ) guard let success = result?.success, success == true else { return } - - promiseInfo.value = result?.data } catch { - print(">>>>> \(error.localizedDescription) : \(#function)") + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } @@ -185,17 +58,19 @@ extension PromiseViewModel { func fetchPromiseParticipantList() { Task { do { - let responseBody = try await service.fetchPromiseParticipantList(with: promiseID) + let responseBody = try await service.fetchPromiseParticipantList( + with: promiseID + ) guard let success = responseBody?.success, success == true else { return } - - participantsInfo.value = responseBody?.data?.participants } catch { - print(">>>>> \(error.localizedDescription) : \(#function)") + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } @@ -204,23 +79,25 @@ extension PromiseViewModel { func fetchMyReadyStatus() { Task { do { - let responseBody = try await service.fetchMyReadyStatus(with: promiseID) + let responseBody = try await service.fetchMyReadyStatus( + with: promiseID + ) guard let success = responseBody?.success, success == true else { return } - - myReadyStatus.value = responseBody?.data } catch { - print(">>>>> \(error.localizedDescription) : \(#function)") + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } /// 준비 시작 업데이트 API 구현 함수 - func updatePreparationStatus(completion: @escaping () -> Void) { + func updatePreparationStatus() { Task { do { let responseBody = try await service.updatePreparationStatus( @@ -232,16 +109,17 @@ extension PromiseViewModel { else { return } - - myReadyProgressStatus.value = .ready - - completion() + } + catch { + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } /// 이동 시작 업데이트 API 구현 함수 - func updateDepartureStatus(completion: @escaping () -> Void) { + func updateDepartureStatus() { Task { do { let responseBody = try await service.updateDepartureStatus( @@ -253,16 +131,19 @@ extension PromiseViewModel { else { return } - - myReadyProgressStatus.value = .move - - completion() + } + catch { + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } /// 도착 완료 업데이트 API 구현 함수 - func updateArrivalStatus(completion: @escaping () -> Void) { + func updateArrivalStatus( + completion: @escaping () -> Void + ) { Task { do { let responseBody = try await service.updateArrivalStatus( @@ -274,10 +155,11 @@ extension PromiseViewModel { else { return } - - myReadyProgressStatus.value = .done - - completion() + } + catch { + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } @@ -286,102 +168,81 @@ extension PromiseViewModel { func fetchTardyInfo() { Task { do { - let responseBody = try await - service.fetchTardyInfo(with: promiseID) + let responseBody = try await service.fetchTardyInfo( + with: promiseID + ) guard let success = responseBody?.success, success == true else { return } - - guard let data = responseBody?.data else { - return - } - - hasTardy.value = !(data.lateComers.isEmpty) - isPastDue.value = data.isPastDue - penalty.value = data.penalty - comers.value = data.lateComers - } catch { - print(">>>>> \(error.localizedDescription) : \(#function)") + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } /// 약속 완료 API 구현 함수 - func updatePromiseCompletion(completion: @escaping () -> Void) { + func updatePromiseCompletion() { Task { do { - let responseBody = try await service.updatePromiseCompletion(with: promiseID) + let responseBody = try await service.updatePromiseCompletion( + with: promiseID + ) guard let success = responseBody?.success, success == true else { - handleError(errorResponse: responseBody?.error) - return } - - completion() } catch { - print(">>>>> \(error.localizedDescription) : \(#function)") + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } - func deletePromise(completion: @escaping () -> Void) { + func deletePromise() { Task { do { - let result = try await service.deletePromise(promiseID: promiseID) + let result = try await service.deletePromise( + promiseID: promiseID + ) guard let success = result?.success, - success == true + success == true else { return } - - completion() + } catch { + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } - func exitPromise(completion: @escaping () -> Void) { + func exitPromise() { Task { do { - let result = try await service.exitPromise(promiseID: promiseID) + let result = try await service.exitPromise( + promiseID: promiseID + ) guard let success = result?.success, success == true else { return } - - completion() + } catch { + print( + ">>>>> \(error.localizedDescription) : \(#function)" + ) } } } } - -private extension PromiseViewModel { - func handleError(errorResponse: ErrorResponse?) { - guard let error = errorResponse else { - errorMessage.value = "알 수 없는 에러" - return - } - - switch error.code { - case 40051: - errorMessage.value = "도착하지 않은 참여자가 있습니다." - case 40050: - errorMessage.value = "약속 시간이 지나지 않았습니다." - case 40340: - errorMessage.value = "참여하지 않은 약속입니다." - case 40450: - errorMessage.value = "약속을 찾을 수 없습니다." - default: - errorMessage.value = "알 수 없는 에러" - } - } -} From 616f68f31995843fa778ca85b1e95add00bc93c0 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 20:37:56 +0900 Subject: [PATCH 03/28] =?UTF-8?q?fix/#388=20PromiseViewController=20?= =?UTF-8?q?=EA=B0=9C=ED=96=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseViewController.swift | 151 ++++-------------- 1 file changed, 35 insertions(+), 116 deletions(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 389a31d1..0c2245af 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -16,47 +16,26 @@ class PromiseViewController: BaseViewController { private let promiseInfoViewController: PromiseInfoViewController private let promiseReadyStatusViewController: ReadyStatusViewController private let promiseTardyViewController: TardyViewController - private let exitViewController = CustomActionSheetController( - kind: .exitPromise - ) - private let deleteViewController = CustomActionSheetController( - kind: .deletePromise - ) + private let exitViewController = CustomActionSheetController(kind: .exitPromise) + private let deleteViewController = CustomActionSheetController(kind: .deletePromise) private let promisePageViewController = UIPageViewController( transitionStyle: .scroll, navigationOrientation: .vertical ) - private var removePromiseViewContoller: RemovePromiseViewController = RemovePromiseViewController( - promiseName: "" - ) + private var removePromiseViewContoller: RemovePromiseViewController = RemovePromiseViewController(promiseName: "") private var promiseViewControllerList: [BaseViewController] = [] - - private lazy var promiseSegmentedControl = PagePromiseSegmentedControl( - items: [ - "약속 정보", - "준비 현황", - "지각 꾸물이" - ] - ) + private lazy var promiseSegmentedControl = PagePromiseSegmentedControl(items: ["약속 정보", "준비 현황", "지각 꾸물이"]) // MARK: - LifeCycle - init( - viewModel: PromiseViewModel - ) { + init(viewModel: PromiseViewModel) { self.viewModel = viewModel - promiseInfoViewController = PromiseInfoViewController( - viewModel: viewModel - ) - promiseReadyStatusViewController = ReadyStatusViewController( - viewModel: viewModel - ) - promiseTardyViewController = TardyViewController( - viewModel: viewModel - ) + promiseInfoViewController = PromiseInfoViewController(viewModel: viewModel) + promiseReadyStatusViewController = ReadyStatusViewController(viewModel: viewModel) + promiseTardyViewController = TardyViewController(viewModel: viewModel) promiseViewControllerList = [ promiseInfoViewController, @@ -64,18 +43,11 @@ class PromiseViewController: BaseViewController { promiseTardyViewController ] - super.init( - nibName: nil, - bundle: nil - ) + super.init(nibName: nil, bundle: nil) } - required init?( - coder: NSCoder - ) { - fatalError( - "init(coder:) has not been implemented" - ) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { @@ -85,22 +57,14 @@ class PromiseViewController: BaseViewController { setupBindings() } - override func viewWillAppear( - _ animated: Bool - ) { - super.viewWillAppear( - animated - ) + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) navigationController?.isNavigationBarHidden = false } - override func viewWillDisappear( - _ animated: Bool - ) { - super.viewWillDisappear( - animated - ) + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) navigationController?.isNavigationBarHidden = true } @@ -111,14 +75,9 @@ class PromiseViewController: BaseViewController { override func setupView() { view.backgroundColor = .white - addChild( - promisePageViewController - ) + addChild(promisePageViewController) - view.addSubviews( - promiseSegmentedControl, - promisePageViewController.view - ) + view.addSubviews(promiseSegmentedControl, promisePageViewController.view) promisePageViewController.setViewControllers( [promiseViewControllerList[0]], @@ -127,23 +86,14 @@ class PromiseViewController: BaseViewController { ) promiseSegmentedControl.snp.makeConstraints { - $0.top.equalTo( - view.safeAreaLayoutGuide - ) - $0.leading.trailing.equalToSuperview().inset( - -6 - ) - $0.height.equalTo( - Screen.height( - 60 - ) + $0.top.equalTo(view.safeAreaLayoutGuide) + $0.leading.trailing.equalToSuperview().inset(-6) + $0.height.equalTo(Screen.height(60) ) } promisePageViewController.view.snp.makeConstraints { - $0.top.equalTo( - promiseSegmentedControl.snp.bottom - ) + $0.top.equalTo(promiseSegmentedControl.snp.bottom) $0.leading.trailing.bottom.equalToSuperview() } } @@ -151,41 +101,31 @@ class PromiseViewController: BaseViewController { override func setupAction() { promiseSegmentedControl.addTarget( self, - action: #selector( - didSegmentedControlIndexUpdated - ), + action: #selector(didSegmentedControlIndexUpdated), for: .valueChanged ) promiseTardyViewController.tardyView.finishMeetingButton.addTarget( self, - action: #selector( - finishMeetingButtonDidTap - ), + action: #selector(finishMeetingButtonDidTap), for: .touchUpInside ) promiseTardyViewController.arriveView.finishMeetingButton.addTarget( self, - action: #selector( - finishMeetingButtonDidTap - ), + action: #selector(finishMeetingButtonDidTap), for: .touchUpInside ) removePromiseViewContoller.exitButton.addTarget( self, - action: #selector( - exitButtonDidTap - ), + action: #selector(exitButtonDidTap), for: .touchUpInside ) removePromiseViewContoller.deleteButton.addTarget( self, - action: #selector( - deleteButtonDidTap - ), + action: #selector(deleteButtonDidTap), for: .touchUpInside ) } @@ -237,37 +177,22 @@ private extension PromiseViewController { func moreButtonDidTap() { let bottomSheetViewController = BottomSheetViewController( contentViewController: removePromiseViewContoller, - defaultHeight: Screen.height( - 232 - ) + defaultHeight: Screen.height(232) ) - present( - bottomSheetViewController, - animated: true - ) + present(bottomSheetViewController, animated: true) } @objc func exitButtonDidTap() { - dismiss( - animated: false - ) - present( - exitViewController, - animated: true - ) + dismiss(animated: false) + present(exitViewController, animated: true) } @objc func deleteButtonDidTap() { - dismiss( - animated: false - ) - present( - deleteViewController, - animated: true - ) + dismiss(animated: false) + present(deleteViewController, animated: true) } } @@ -275,18 +200,12 @@ private extension PromiseViewController { // MARK: - CustomActionSheetDelegate extension PromiseViewController: CustomActionSheetDelegate { - func actionButtonDidTap( - for kind: ActionSheetKind - ) { + func actionButtonDidTap(for kind: ActionSheetKind) { if kind == .deletePromise { - dismiss( - animated: false - ) + dismiss(animated: false) } else { - dismiss( - animated: false - ) + dismiss(animated: false) } } } From 84f007b7702b94f1503d85b8fb8ab3a01996fc09 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 21:07:22 +0900 Subject: [PATCH 04/28] =?UTF-8?q?fix/#388=20PromiseViewModel=20=EA=B0=9C?= =?UTF-8?q?=ED=96=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Promise/ViewModel/PromiseViewModel.swift | 90 +++++-------------- 1 file changed, 22 insertions(+), 68 deletions(-) diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 4e2fd9a4..6c8c4b85 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -12,7 +12,6 @@ class PromiseViewModel { // MARK: Property - /// 서버 통신을 위해 생성자로 주입받을 약속 ID let promiseID: Int private let service: PromiseServiceProtocol @@ -20,10 +19,7 @@ class PromiseViewModel { // MARK: Initialize - init( - promiseID: Int, - service: PromiseServiceProtocol - ) { + init(promiseID: Int, service: PromiseServiceProtocol) { self.service = service self.promiseID = promiseID } @@ -37,9 +33,7 @@ extension PromiseViewModel { func fetchPromiseInfo() { Task { do { - let result = try await service.fetchPromiseInfo( - with: promiseID - ) + let result = try await service.fetchPromiseInfo(with: promiseID) guard let success = result?.success, success == true @@ -47,9 +41,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -58,9 +50,7 @@ extension PromiseViewModel { func fetchPromiseParticipantList() { Task { do { - let responseBody = try await service.fetchPromiseParticipantList( - with: promiseID - ) + let responseBody = try await service.fetchPromiseParticipantList(with: promiseID) guard let success = responseBody?.success, success == true @@ -68,9 +58,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -79,9 +67,7 @@ extension PromiseViewModel { func fetchMyReadyStatus() { Task { do { - let responseBody = try await service.fetchMyReadyStatus( - with: promiseID - ) + let responseBody = try await service.fetchMyReadyStatus(with: promiseID) guard let success = responseBody?.success, success == true @@ -89,9 +75,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -100,9 +84,7 @@ extension PromiseViewModel { func updatePreparationStatus() { Task { do { - let responseBody = try await service.updatePreparationStatus( - with: promiseID - ) + let responseBody = try await service.updatePreparationStatus(with: promiseID) guard let success = responseBody?.success, success == true @@ -111,9 +93,7 @@ extension PromiseViewModel { } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -122,9 +102,7 @@ extension PromiseViewModel { func updateDepartureStatus() { Task { do { - let responseBody = try await service.updateDepartureStatus( - with: promiseID - ) + let responseBody = try await service.updateDepartureStatus(with: promiseID) guard let success = responseBody?.success, success == true @@ -133,22 +111,16 @@ extension PromiseViewModel { } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } /// 도착 완료 업데이트 API 구현 함수 - func updateArrivalStatus( - completion: @escaping () -> Void - ) { + func updateArrivalStatus() { Task { do { - let responseBody = try await service.updateArrivalStatus( - with: promiseID - ) + let responseBody = try await service.updateArrivalStatus(with: promiseID) guard let success = responseBody?.success, success == true @@ -157,9 +129,7 @@ extension PromiseViewModel { } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -168,9 +138,7 @@ extension PromiseViewModel { func fetchTardyInfo() { Task { do { - let responseBody = try await service.fetchTardyInfo( - with: promiseID - ) + let responseBody = try await service.fetchTardyInfo(with: promiseID) guard let success = responseBody?.success, success == true @@ -178,9 +146,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -189,9 +155,7 @@ extension PromiseViewModel { func updatePromiseCompletion() { Task { do { - let responseBody = try await service.updatePromiseCompletion( - with: promiseID - ) + let responseBody = try await service.updatePromiseCompletion(with: promiseID) guard let success = responseBody?.success, success == true @@ -199,9 +163,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -209,9 +171,7 @@ extension PromiseViewModel { func deletePromise() { Task { do { - let result = try await service.deletePromise( - promiseID: promiseID - ) + let result = try await service.deletePromise(promiseID: promiseID) guard let success = result?.success, success == true @@ -219,9 +179,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } @@ -229,9 +187,7 @@ extension PromiseViewModel { func exitPromise() { Task { do { - let result = try await service.exitPromise( - promiseID: promiseID - ) + let result = try await service.exitPromise(promiseID: promiseID) guard let success = result?.success, success == true @@ -239,9 +195,7 @@ extension PromiseViewModel { return } } catch { - print( - ">>>>> \(error.localizedDescription) : \(#function)" - ) + print(">>>>> \(error.localizedDescription) : \(#function)") } } } From 918f77c5e2ab485ba53fb5055e0c73fc983956df Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 21:14:27 +0900 Subject: [PATCH 05/28] =?UTF-8?q?fix/#388=20ReadyStatusViewController,=20T?= =?UTF-8?q?radyViewController=20=EA=B0=9C=ED=96=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyStatusViewController.swift | 45 +++++-------------- .../ViewController/TardyViewController.swift | 35 ++++----------- 2 files changed, 19 insertions(+), 61 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index d2451fc5..bd5c14f4 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -20,23 +20,14 @@ class ReadyStatusViewController: BaseViewController { // MARK: - LifeCycle - init( - viewModel: PromiseViewModel - ) { + init(viewModel: PromiseViewModel) { self.viewModel = viewModel - super.init( - nibName: nil, - bundle: nil - ) + super.init(nibName: nil, bundle: nil) } - required init?( - coder: NSCoder - ) { - fatalError( - "init(coder:) has not been implemented" - ) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") } override func loadView() { @@ -51,12 +42,8 @@ class ReadyStatusViewController: BaseViewController { setupBinding() } - override func viewWillAppear( - _ animated: Bool - ) { - super.viewWillAppear( - animated - ) + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) } override func viewDidLayoutSubviews() { @@ -74,38 +61,28 @@ class ReadyStatusViewController: BaseViewController { override func setupAction() { rootView.myReadyStatusProgressView.readyStartButton.addTarget( self, - action: #selector( - readyStartButtonDidTap - ), + action: #selector(readyStartButtonDidTap), for: .touchUpInside ) rootView.myReadyStatusProgressView.moveStartButton.addTarget( self, - action: #selector( - moveStartButtonDidTap - ), + action: #selector(moveStartButtonDidTap), for: .touchUpInside ) rootView.myReadyStatusProgressView.arrivalButton.addTarget( self, - action: #selector( - arrivalButtonDidTap - ), + action: #selector(arrivalButtonDidTap), for: .touchUpInside ) rootView.readyPlanInfoView.editButton.addTarget( self, - action: #selector( - editReadyButtonDidTap - ), + action: #selector(editReadyButtonDidTap), for: .touchUpInside ) rootView.enterReadyButtonView.addGestureRecognizer( UITapGestureRecognizer( target: self, - action: #selector( - enterReadyButtonDidTap - ) + action: #selector(enterReadyButtonDidTap) ) ) } diff --git a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift index 4df2a9bb..80ba5879 100644 --- a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift +++ b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift @@ -19,23 +19,14 @@ class TardyViewController: BaseViewController { // MARK: - LifeCycle - init( - viewModel: PromiseViewModel - ) { + init(viewModel: PromiseViewModel) { self.viewModel = viewModel - super.init( - nibName: nil, - bundle: nil - ) + super.init(nibName: nil, bundle: nil) } - required init?( - coder: NSCoder - ) { - fatalError( - "init(coder:) has not been implemented" - ) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { @@ -44,12 +35,8 @@ class TardyViewController: BaseViewController { setupBinding() } - override func viewWillAppear( - _ animated: Bool - ) { - super.viewWillAppear( - animated - ) + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) viewModel.fetchTardyInfo() } @@ -58,15 +45,9 @@ class TardyViewController: BaseViewController { // MARK: - Setup override func setupView() { - view.addSubviews( - arriveView, - tardyView - ) + view.addSubviews(arriveView, tardyView) - [ - arriveView, - tardyView - ].forEach { + [arriveView, tardyView].forEach { $0.snp.makeConstraints { $0.edges.equalToSuperview() } From 5fbe45a458c216affc982b07a60408a1221ba938 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 21:40:44 +0900 Subject: [PATCH 06/28] =?UTF-8?q?feat/#388=20=EC=95=BD=EC=86=8D=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=82=B4=20=EC=95=BD=EC=86=8D=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=95=BD=EC=86=8D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/PromiseViewController.swift | 17 ++++++++++++++--- .../Promise/ViewModel/PromiseViewModel.swift | 9 +++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 0c2245af..94041103 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -54,7 +54,7 @@ class PromiseViewController: BaseViewController { super.viewDidLoad() setupNavigationBarBackButton() - setupBindings() + setupBinding() } override func viewWillAppear(_ animated: Bool) { @@ -141,8 +141,19 @@ class PromiseViewController: BaseViewController { // MARK: - Extension private extension PromiseViewController { - func setupBindings() { - + func setupBinding() { + viewModel.promiseInfo.bindOnMain(with: self) { owner, info in + guard let isParticipant = info?.isParticipant else { return } + + let moreButton = UIBarButtonItem( + image: .imgMore.withRenderingMode(.alwaysOriginal), + style: .plain, + target: owner, + action: #selector(owner.moreButtonDidTap) + ) + + owner.navigationController?.navigationItem.rightBarButtonItem = isParticipant ? moreButton : nil + } } @objc diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 6c8c4b85..7096d710 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -13,6 +13,7 @@ class PromiseViewModel { // MARK: Property let promiseID: Int + let promiseInfo = ObservablePattern(nil) private let service: PromiseServiceProtocol @@ -38,11 +39,17 @@ extension PromiseViewModel { guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") + return } + + promiseInfo.value = result?.data } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } + + } } @@ -168,6 +175,7 @@ extension PromiseViewModel { } } + /// 약속 삭제 API 구현 함수 func deletePromise() { Task { do { @@ -184,6 +192,7 @@ extension PromiseViewModel { } } + /// 약속 나가기 API 구현 함수 func exitPromise() { Task { do { From d7e8821e7238d3bf52079a28c9f6a35e4ff7fc35 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 21:46:28 +0900 Subject: [PATCH 07/28] =?UTF-8?q?fix/#388=20promiseInfoViewController=20?= =?UTF-8?q?=EA=B0=9C=ED=96=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseInfoViewController.swift | 51 +++++-------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 93a8926e..2267102b 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -14,29 +14,20 @@ class PromiseInfoViewController: BaseViewController { // MARK: Property - let rootView: PromiseInfoView = PromiseInfoView() - let viewModel: PromiseViewModel + private let viewModel: PromiseViewModel + private let rootView: PromiseInfoView = PromiseInfoView() // MARK: - LifeCycle - init( - viewModel: PromiseViewModel - ) { + init(viewModel: PromiseViewModel) { self.viewModel = viewModel - super.init( - nibName: nil, - bundle: nil - ) + super.init(nibName: nil, bundle: nil) } - required init?( - coder: NSCoder - ) { - fatalError( - "init(coder:) has not been implemented" - ) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") } override func loadView() { @@ -49,12 +40,8 @@ class PromiseInfoViewController: BaseViewController { setupBinding() } - override func viewWillAppear( - _ animated: Bool - ) { - super.viewWillAppear( - animated - ) + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) } @@ -72,9 +59,7 @@ class PromiseInfoViewController: BaseViewController { override func setupAction() { rootView.editButton.addTarget( self, - action: #selector( - editButtonDidTap - ), + action: #selector(editButtonDidTap), for: .touchUpInside ) } @@ -84,12 +69,12 @@ class PromiseInfoViewController: BaseViewController { // MARK: - Extension extension PromiseInfoViewController { - @objc - func editButtonDidTap() { + func setupBinding() { } - func setupBinding() { + @objc + func editButtonDidTap() { } } @@ -112,8 +97,7 @@ extension PromiseInfoViewController: UICollectionViewDataSource { guard let cell = collectionView.dequeueReusableCell( withReuseIdentifier: ParticipantCollectionViewCell.reuseIdentifier, for: indexPath - ) as? ParticipantCollectionViewCell - else { + ) as? ParticipantCollectionViewCell else { return UICollectionViewCell() } @@ -130,14 +114,7 @@ extension PromiseInfoViewController: UICollectionViewDelegateFlowLayout { layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath ) -> CGSize { - return CGSize( - width: Screen.width( - 68 - ), - height: Screen.height( - 88 - ) - ) + return CGSize(width: Screen.width(68), height: Screen.height(88)) } } From b566408317f84de3faf5ea61d5e3e87f85455b78 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 22:53:30 +0900 Subject: [PATCH 08/28] =?UTF-8?q?refactor/#388=20=EC=95=BD=EC=86=8D=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20ViewController=20=EC=9E=AC=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseInfo/View/PromiseInfoView.swift | 8 +- .../PromiseInfoViewController.swift | 78 ++++++++++++++++++- .../Promise/ViewModel/PromiseViewModel.swift | 71 ++++++++++++----- 3 files changed, 134 insertions(+), 23 deletions(-) diff --git a/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift b/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift index 04b4045f..023ad792 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift @@ -68,7 +68,7 @@ class PromiseInfoView: BaseView { $0.layer.cornerRadius = Screen.height(18) } - private let locationInfoLabel: UILabel = UILabel().then { + let locationInfoLabel: UILabel = UILabel().then { $0.setText("위치", style: .body05, color: .maincolor) } @@ -77,7 +77,7 @@ class PromiseInfoView: BaseView { $0.layer.cornerRadius = Screen.height(8) } - private let timeInfoLabel: UILabel = UILabel().then { + let timeInfoLabel: UILabel = UILabel().then { $0.setText("약속시간", style: .body05, color: .maincolor) } @@ -86,7 +86,7 @@ class PromiseInfoView: BaseView { $0.layer.cornerRadius = Screen.height(8) } - private let readyLevelInfoLabel: UILabel = UILabel().then { + let readyLevelInfoLabel: UILabel = UILabel().then { $0.setText("꾸레벨", style: .body05, color: .maincolor) } @@ -95,7 +95,7 @@ class PromiseInfoView: BaseView { $0.layer.cornerRadius = Screen.height(8) } - private let penaltyLevelInfoLabel: UILabel = UILabel().then { + let penaltyLevelInfoLabel: UILabel = UILabel().then { $0.setText("벌칙", style: .body05, color: .maincolor) } diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 2267102b..5cebd940 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -42,6 +42,9 @@ class PromiseInfoViewController: BaseViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + + viewModel.fetchPromiseInfo() + viewModel.fetchPromiseParticipantList() } @@ -70,12 +73,77 @@ class PromiseInfoViewController: BaseViewController { extension PromiseInfoViewController { func setupBinding() { + viewModel.promiseInfo.bindOnMain(with: self) { owner, info in + guard let info else { return } + + owner.rootView.editButton.isHidden = !(info.isParticipant) + + owner.rootView.promiseNameLabel.setText(info.promiseName, style: .body01) + owner.rootView.locationContentLabel.setText(info.placeName, style: .body04) + owner.rootView.readyLevelContentLabel.setText(info.dressUpLevel, style: .body04) + owner.rootView.penaltyLevelContentLabel.setText(info.penalty, style: .body04) + owner.rootView.timeContentLabel.setText(info.time, style: .body04) + } + + viewModel.dDay.bindOnMain(with: self) { owner, dDay in + guard let dDay else { return } + + switch dDay { + case 1...: + owner.rootView.dDayLabel.setText("D+\(-dDay)", style: .body05, color: .gray4) + owner.rootView.promiseImageView.image = .imgPromiseGray + owner.rootView.promiseNameLabel.textColor = .gray4 + owner.rootView.locationInfoLabel.textColor = .gray4 + owner.rootView.timeInfoLabel.textColor = .gray4 + owner.rootView.readyLevelInfoLabel.textColor = .gray4 + owner.rootView.penaltyLevelInfoLabel.textColor = .gray4 + case 0: + owner.rootView.dDayLabel.setText("D-DAY", style: .body05, color: .mainorange) + case ..<0: + owner.rootView.dDayLabel.setText("D-\(dDay)", style: .body05, color: .gray5) + default: + break + } + } + viewModel.participants.bindOnMain(with: self) { owner, _ in + owner.rootView.participantCollectionView.reloadData() + } } @objc func editButtonDidTap() { + guard var dressUpLevel = viewModel.promiseInfo.value?.dressUpLevel else { return } + + let levels = ["LV1", "LV2", "LV3", "LV4", "FREE"] + if dressUpLevel.contains("마음대로 입고 오기") { + dressUpLevel = "FREE" + } else { + if let matched = levels.first(where: { level in + dressUpLevel.replacingOccurrences(of: " ", with: "").contains(level) + }) { + dressUpLevel = matched + } + } + + let viewController = EditPromiseViewController( + viewModel: EditPromiseViewModel( + promiseID: viewModel.promiseID, + promiseName: viewModel.promiseInfo.value?.promiseName, + placeName: viewModel.promiseInfo.value?.placeName, + xCoordinate: viewModel.promiseInfo.value?.x, + yCoordinate: viewModel.promiseInfo.value?.y, + address: viewModel.promiseInfo.value?.address, + roadAddress: viewModel.promiseInfo.value?.roadAddress, + time: viewModel.promiseInfo.value?.time, + dressUpLevel: dressUpLevel, + penalty: viewModel.promiseInfo.value?.penalty, + service: PromiseService() + ) + ) + + navigationController?.pushViewController(viewController, animated: true) } } @@ -87,7 +155,7 @@ extension PromiseInfoViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - return 0 + return viewModel.participants.value.count } func collectionView( @@ -101,6 +169,14 @@ extension PromiseInfoViewController: UICollectionViewDataSource { return UICollectionViewCell() } + let info = viewModel.participants.value[indexPath.row] + + cell.userNameLabel.setText(info.name, style: .caption02, color: .gray6) + cell.profileImageView.kf.setImage( + with: URL(string: info.profileImageURL ?? ""), + placeholder: UIImage.imgProfile + ) + return cell } } diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 7096d710..20123162 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -14,6 +14,8 @@ class PromiseViewModel { let promiseID: Int let promiseInfo = ObservablePattern(nil) + let participants = ObservablePattern<[Participant]>([]) + let dDay = ObservablePattern(nil) private let service: PromiseServiceProtocol @@ -29,6 +31,24 @@ class PromiseViewModel { // MARK: - Extension +private extension PromiseViewModel { + func calculateDday() { + let calendar = Calendar.current + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + dateFormatter.locale = Locale(identifier: "ko_KR") + dateFormatter.timeZone = TimeZone(identifier: "Asia/Seoul") + + guard let dateWithTime = dateFormatter.date(from: promiseInfo.value?.time ?? "") else { return } + + let dateOnly = calendar.startOfDay(for: dateWithTime) + let today = calendar.startOfDay(for: Date()) + let components = calendar.dateComponents([.day], from: today, to: dateOnly) + + dDay.value = components.day + } +} + extension PromiseViewModel { /// 약속 상세 정보 조회 API 구현 함수 func fetchPromiseInfo() { @@ -40,16 +60,15 @@ extension PromiseViewModel { success == true else { print(">>>>> \(String(describing: result)) : \(#function)") - return } promiseInfo.value = result?.data + + calculateDday() } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } - - } } @@ -57,13 +76,21 @@ extension PromiseViewModel { func fetchPromiseParticipantList() { Task { do { - let responseBody = try await service.fetchPromiseParticipantList(with: promiseID) + let result = try await service.fetchPromiseParticipantList(with: promiseID) - guard let success = responseBody?.success, - success == true + guard let success = result?.success, + success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") + return + } + + guard let data = result?.data else { + print(">>>>> \("데이터 없음") : \(#function)") return } + + participants.value = data.participants } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } @@ -74,11 +101,12 @@ extension PromiseViewModel { func fetchMyReadyStatus() { Task { do { - let responseBody = try await service.fetchMyReadyStatus(with: promiseID) + let result = try await service.fetchMyReadyStatus(with: promiseID) - guard let success = responseBody?.success, + guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } catch { @@ -91,11 +119,12 @@ extension PromiseViewModel { func updatePreparationStatus() { Task { do { - let responseBody = try await service.updatePreparationStatus(with: promiseID) + let result = try await service.updatePreparationStatus(with: promiseID) - guard let success = responseBody?.success, + guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } @@ -109,11 +138,12 @@ extension PromiseViewModel { func updateDepartureStatus() { Task { do { - let responseBody = try await service.updateDepartureStatus(with: promiseID) + let result = try await service.updateDepartureStatus(with: promiseID) - guard let success = responseBody?.success, + guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } @@ -127,11 +157,12 @@ extension PromiseViewModel { func updateArrivalStatus() { Task { do { - let responseBody = try await service.updateArrivalStatus(with: promiseID) + let result = try await service.updateArrivalStatus(with: promiseID) - guard let success = responseBody?.success, + guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } @@ -145,11 +176,12 @@ extension PromiseViewModel { func fetchTardyInfo() { Task { do { - let responseBody = try await service.fetchTardyInfo(with: promiseID) + let result = try await service.fetchTardyInfo(with: promiseID) - guard let success = responseBody?.success, + guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } catch { @@ -162,11 +194,12 @@ extension PromiseViewModel { func updatePromiseCompletion() { Task { do { - let responseBody = try await service.updatePromiseCompletion(with: promiseID) + let result = try await service.updatePromiseCompletion(with: promiseID) - guard let success = responseBody?.success, + guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } catch { @@ -184,6 +217,7 @@ extension PromiseViewModel { guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } catch { @@ -201,6 +235,7 @@ extension PromiseViewModel { guard let success = result?.success, success == true else { + print(">>>>> \(String(describing: result)) : \(#function)") return } } catch { From 3ee91c4cc626bbe2245b2b67c2d33d08cfff9632 Mon Sep 17 00:00:00 2001 From: youz2me Date: Sun, 15 Sep 2024 22:56:19 +0900 Subject: [PATCH 09/28] =?UTF-8?q?fix/#388=20MARK=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseInfo/ViewController/PromiseInfoViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 5cebd940..41749a3d 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -12,7 +12,7 @@ import Kingfisher class PromiseInfoViewController: BaseViewController { - // MARK: Property + // MARK: - Property private let viewModel: PromiseViewModel private let rootView: PromiseInfoView = PromiseInfoView() From cee734393bd3b9025c1548d1a0cda18ce6b143a0 Mon Sep 17 00:00:00 2001 From: youz2me Date: Mon, 16 Sep 2024 00:16:43 +0900 Subject: [PATCH 10/28] =?UTF-8?q?fix/#388=20=EC=95=BD=EC=86=8D=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EB=B0=94=20=EC=9D=B4=EB=A6=84=20=EC=95=88=EB=9C=A8=EB=8A=94=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0,=20=EC=95=BD=EC=86=8D?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=A0=95=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=20=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseViewController.swift | 13 +++------- .../PromiseInfoViewController.swift | 22 +++++++++------- .../Promise/ViewModel/PromiseViewModel.swift | 26 +++++++++++++++++-- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 94041103..71a3eb10 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -105,13 +105,7 @@ class PromiseViewController: BaseViewController { for: .valueChanged ) - promiseTardyViewController.tardyView.finishMeetingButton.addTarget( - self, - action: #selector(finishMeetingButtonDidTap), - for: .touchUpInside - ) - - promiseTardyViewController.arriveView.finishMeetingButton.addTarget( + promiseTardyViewController.rootView.finishMeetingButton.addTarget( self, action: #selector(finishMeetingButtonDidTap), for: .touchUpInside @@ -143,7 +137,7 @@ class PromiseViewController: BaseViewController { private extension PromiseViewController { func setupBinding() { viewModel.promiseInfo.bindOnMain(with: self) { owner, info in - guard let isParticipant = info?.isParticipant else { return } + guard let info else { return } let moreButton = UIBarButtonItem( image: .imgMore.withRenderingMode(.alwaysOriginal), @@ -152,7 +146,8 @@ private extension PromiseViewController { action: #selector(owner.moreButtonDidTap) ) - owner.navigationController?.navigationItem.rightBarButtonItem = isParticipant ? moreButton : nil + owner.navigationController?.navigationItem.rightBarButtonItem = info.isParticipant ? moreButton : nil + owner.setupNavigationBarTitle(with: info.promiseName, isBorderHidden: true) } } diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 41749a3d..3316efa2 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -43,6 +43,7 @@ class PromiseInfoViewController: BaseViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + viewModel.fetchTardyInfo() viewModel.fetchPromiseInfo() viewModel.fetchPromiseParticipantList() } @@ -76,8 +77,7 @@ extension PromiseInfoViewController { viewModel.promiseInfo.bindOnMain(with: self) { owner, info in guard let info else { return } - owner.rootView.editButton.isHidden = !(info.isParticipant) - + owner.rootView.editButton.isHidden = owner.viewModel.isEditButtonHidden() owner.rootView.promiseNameLabel.setText(info.promiseName, style: .body01) owner.rootView.locationContentLabel.setText(info.placeName, style: .body04) owner.rootView.readyLevelContentLabel.setText(info.dressUpLevel, style: .body04) @@ -90,6 +90,10 @@ extension PromiseInfoViewController { switch dDay { case 1...: + owner.rootView.dDayLabel.setText("D-\(dDay)", style: .body05, color: .gray5) + case 0: + owner.rootView.dDayLabel.setText("D-DAY", style: .body05, color: .mainorange) + case ..<0: owner.rootView.dDayLabel.setText("D+\(-dDay)", style: .body05, color: .gray4) owner.rootView.promiseImageView.image = .imgPromiseGray owner.rootView.promiseNameLabel.textColor = .gray4 @@ -97,18 +101,18 @@ extension PromiseInfoViewController { owner.rootView.timeInfoLabel.textColor = .gray4 owner.rootView.readyLevelInfoLabel.textColor = .gray4 owner.rootView.penaltyLevelInfoLabel.textColor = .gray4 - case 0: - owner.rootView.dDayLabel.setText("D-DAY", style: .body05, color: .mainorange) - case ..<0: - owner.rootView.dDayLabel.setText("D-\(dDay)", style: .body05, color: .gray5) default: break } } - viewModel.participants.bindOnMain(with: self) { owner, _ in + viewModel.participantList.bindOnMain(with: self) { owner, _ in owner.rootView.participantCollectionView.reloadData() } + + viewModel.isPastDue.bindOnMain(with: self) { owner, _ in + owner.rootView.editButton.isHidden = owner.viewModel.isEditButtonHidden() + } } @objc @@ -155,7 +159,7 @@ extension PromiseInfoViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - return viewModel.participants.value.count + return viewModel.participantList.value.count } func collectionView( @@ -169,7 +173,7 @@ extension PromiseInfoViewController: UICollectionViewDataSource { return UICollectionViewCell() } - let info = viewModel.participants.value[indexPath.row] + let info = viewModel.participantList.value[indexPath.row] cell.userNameLabel.setText(info.name, style: .caption02, color: .gray6) cell.profileImageView.kf.setImage( diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 20123162..1bd41782 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -14,8 +14,11 @@ class PromiseViewModel { let promiseID: Int let promiseInfo = ObservablePattern(nil) - let participants = ObservablePattern<[Participant]>([]) + let isPastDue = ObservablePattern(nil) + let penalty = ObservablePattern(nil) let dDay = ObservablePattern(nil) + let participantList = ObservablePattern<[Participant]>([]) + let tardyList = ObservablePattern<[Comer]>([]) private let service: PromiseServiceProtocol @@ -50,6 +53,16 @@ private extension PromiseViewModel { } extension PromiseViewModel { + func isEditButtonHidden() -> Bool { + guard let isParticipant = promiseInfo.value?.isParticipant, + let isPastDue = isPastDue.value + else { + return false + } + + return !(isParticipant && !isPastDue) + } + /// 약속 상세 정보 조회 API 구현 함수 func fetchPromiseInfo() { Task { @@ -90,7 +103,7 @@ extension PromiseViewModel { return } - participants.value = data.participants + participantList.value = data.participants } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } @@ -184,6 +197,15 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + guard let data = result?.data else { + print(">>>>> \("데이터 없음") : \(#function)") + return + } + + penalty.value = data.penalty + isPastDue.value = data.isPastDue + tardyList.value = data.lateComers } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } From 89764bc0e1575e9fd1a66531e5b6130031b8f5eb Mon Sep 17 00:00:00 2001 From: youz2me Date: Mon, 16 Sep 2024 22:39:42 +0900 Subject: [PATCH 11/28] =?UTF-8?q?refactor/#388=20=EC=A7=80=EA=B0=81=20?= =?UTF-8?q?=EA=BE=B8=EB=AC=BC=EC=9D=B4=20=EB=B7=B0=20=ED=95=98=EB=82=98?= =?UTF-8?q?=EB=A1=9C=20=ED=95=A9=EC=B3=90=EC=A7=80=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum.xcodeproj/project.pbxproj | 8 +++---- .../{ArriveView.swift => NoTardyView.swift} | 21 +++---------------- .../Source/Promise/Tardy/View/TardyView.swift | 7 +++++++ .../ViewController/TardyViewController.swift | 19 ++++++----------- 4 files changed, 20 insertions(+), 35 deletions(-) rename KkuMulKum/Source/Promise/Tardy/View/{ArriveView.swift => NoTardyView.swift} (71%) diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index d019b288..f6050b5b 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -152,7 +152,7 @@ DD43937C2C412F4500EC1799 /* InviteCodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4393742C412F4500EC1799 /* InviteCodeViewController.swift */; }; DD43937D2C412F4500EC1799 /* CheckInviteCodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4393752C412F4500EC1799 /* CheckInviteCodeViewController.swift */; }; DD43937F2C41357800EC1799 /* InviteCodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD43937E2C41357800EC1799 /* InviteCodeViewModel.swift */; }; - DD4909962C440CDC003ED304 /* ArriveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4909952C440CDC003ED304 /* ArriveView.swift */; }; + DD4909962C440CDC003ED304 /* NoTardyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4909952C440CDC003ED304 /* NoTardyView.swift */; }; DD8626612C4606A300E4F980 /* SetReadyInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8626522C4606A300E4F980 /* SetReadyInfoViewModel.swift */; }; DD8626632C4606A300E4F980 /* EnterReadyInfoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8626552C4606A300E4F980 /* EnterReadyInfoButtonView.swift */; }; DD8626642C4606A300E4F980 /* ReadyPlanInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8626562C4606A300E4F980 /* ReadyPlanInfoView.swift */; }; @@ -371,7 +371,7 @@ DD4393742C412F4500EC1799 /* InviteCodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InviteCodeViewController.swift; sourceTree = ""; }; DD4393752C412F4500EC1799 /* CheckInviteCodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckInviteCodeViewController.swift; sourceTree = ""; }; DD43937E2C41357800EC1799 /* InviteCodeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteCodeViewModel.swift; sourceTree = ""; }; - DD4909952C440CDC003ED304 /* ArriveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArriveView.swift; sourceTree = ""; }; + DD4909952C440CDC003ED304 /* NoTardyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoTardyView.swift; sourceTree = ""; }; DD8626522C4606A300E4F980 /* SetReadyInfoViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetReadyInfoViewModel.swift; sourceTree = ""; }; DD8626552C4606A300E4F980 /* EnterReadyInfoButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnterReadyInfoButtonView.swift; sourceTree = ""; }; DD8626562C4606A300E4F980 /* ReadyPlanInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadyPlanInfoView.swift; sourceTree = ""; }; @@ -803,7 +803,7 @@ DD41BEF92C41D4160095A068 /* TardyView.swift */, DD41BEFB2C41D54D0095A068 /* TardyPenaltyView.swift */, DD41BEFE2C41DAA40095A068 /* TardyEmptyView.swift */, - DD4909952C440CDC003ED304 /* ArriveView.swift */, + DD4909952C440CDC003ED304 /* NoTardyView.swift */, ); path = View; sourceTree = ""; @@ -2039,7 +2039,7 @@ DE9E18802C3BA4AA00DB76B4 /* CustomButton.swift in Sources */, DE0137D32C43C5E50088C777 /* MyPageView.swift in Sources */, DE558C592C45954B008DAC4A /* SelectMemberViewController.swift in Sources */, - DD4909962C440CDC003ED304 /* ArriveView.swift in Sources */, + DD4909962C440CDC003ED304 /* NoTardyView.swift in Sources */, 789196342C486F6B00FF8CDF /* KeychainAccessible.swift in Sources */, DE254AB02C31195B00A4015E /* NSAttributedString+.swift in Sources */, DD43937B2C412F4500EC1799 /* CreateMeetingViewController.swift in Sources */, diff --git a/KkuMulKum/Source/Promise/Tardy/View/ArriveView.swift b/KkuMulKum/Source/Promise/Tardy/View/NoTardyView.swift similarity index 71% rename from KkuMulKum/Source/Promise/Tardy/View/ArriveView.swift rename to KkuMulKum/Source/Promise/Tardy/View/NoTardyView.swift index 919e3daf..b7c7d2a3 100644 --- a/KkuMulKum/Source/Promise/Tardy/View/ArriveView.swift +++ b/KkuMulKum/Source/Promise/Tardy/View/NoTardyView.swift @@ -1,5 +1,5 @@ // -// ArriveView.swift +// NoTardyView.swift // KkuMulKum // // Created by YOUJIM on 7/14/24. @@ -7,18 +7,11 @@ import UIKit -class ArriveView: BaseView { +class NoTardyView: BaseView { // MARK: Property - let finishMeetingButton: CustomButton = CustomButton( - title: "약속 마치기", - isEnabled: true - ).then { - $0.backgroundColor = .maincolor - } - private let giftImageView: UIImageView = UIImageView().then { $0.image = .imgGift $0.contentMode = .scaleAspectFit @@ -41,8 +34,7 @@ class ArriveView: BaseView { addSubviews( giftImageView, mainTitleLabel, - subTitleLabel, - finishMeetingButton + subTitleLabel ) } @@ -63,12 +55,5 @@ class ArriveView: BaseView { $0.top.equalTo(mainTitleLabel.snp.bottom).offset(4) $0.centerX.equalToSuperview() } - - finishMeetingButton.snp.makeConstraints { - $0.bottom.equalToSuperview().inset(64) - $0.centerX.equalToSuperview() - $0.height.equalTo(CustomButton.defaultHeight) - $0.width.equalTo(CustomButton.defaultWidth) - } } } diff --git a/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift b/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift index 22ec581f..edf6b8f7 100644 --- a/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift +++ b/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift @@ -18,6 +18,8 @@ class TardyView: BaseView { let tardyEmptyView: TardyEmptyView = TardyEmptyView() + let noTardyView: NoTardyView = NoTardyView() + let tardyCollectionView: UICollectionView = UICollectionView( frame: .zero, collectionViewLayout: UICollectionViewFlowLayout().then { @@ -54,6 +56,7 @@ class TardyView: BaseView { tardyPenaltyView, titleLabel, tardyEmptyView, + noTardyView, tardyCollectionView, finishMeetingButton ) @@ -78,6 +81,10 @@ class TardyView: BaseView { $0.width.equalTo(Screen.width(112)) } + noTardyView.snp.makeConstraints { + $0.edges.equalTo(safeAreaLayoutGuide) + } + finishMeetingButton.snp.makeConstraints { $0.bottom.equalToSuperview().inset(64) $0.centerX.equalToSuperview() diff --git a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift index 80ba5879..cdcb74c6 100644 --- a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift +++ b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift @@ -13,8 +13,7 @@ class TardyViewController: BaseViewController { // MARK: Property let viewModel: PromiseViewModel - let tardyView: TardyView = TardyView() - let arriveView: ArriveView = ArriveView() + let rootView: TardyView = TardyView() // MARK: - LifeCycle @@ -29,6 +28,10 @@ class TardyViewController: BaseViewController { fatalError("init(coder:) has not been implemented") } + override func loadView() { + view = rootView + } + override func viewDidLoad() { super.viewDidLoad() @@ -44,18 +47,8 @@ class TardyViewController: BaseViewController { // MARK: - Setup - override func setupView() { - view.addSubviews(arriveView, tardyView) - - [arriveView, tardyView].forEach { - $0.snp.makeConstraints { - $0.edges.equalToSuperview() - } - } - } - override func setupDelegate() { - tardyView.tardyCollectionView.dataSource = self + rootView.tardyCollectionView.dataSource = self } } From e81ec576f23af387683926a6b53eadf1b8ce0a3a Mon Sep 17 00:00:00 2001 From: youz2me Date: Tue, 17 Sep 2024 00:11:36 +0900 Subject: [PATCH 12/28] =?UTF-8?q?refactor/#388=20SegmentedControl=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20Observabl?= =?UTF-8?q?e=20Pattern=20=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseViewController.swift | 38 +++++++++---------- .../Promise/ViewModel/PromiseViewModel.swift | 3 ++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 71a3eb10..901a206e 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -22,7 +22,6 @@ class PromiseViewController: BaseViewController { transitionStyle: .scroll, navigationOrientation: .vertical ) - private var removePromiseViewContoller: RemovePromiseViewController = RemovePromiseViewController(promiseName: "") private var promiseViewControllerList: [BaseViewController] = [] private lazy var promiseSegmentedControl = PagePromiseSegmentedControl(items: ["약속 정보", "준비 현황", "지각 꾸물이"]) @@ -149,29 +148,28 @@ private extension PromiseViewController { owner.navigationController?.navigationItem.rightBarButtonItem = info.isParticipant ? moreButton : nil owner.setupNavigationBarTitle(with: info.promiseName, isBorderHidden: true) } + + viewModel.currentPageIndex.bindOnMain(with: self) { owner, index in + let direction: UIPageViewController.NavigationDirection = owner.viewModel.pageControlDirection ? .forward : .reverse + let (width, count) = ( + owner.promiseSegmentedControl.bounds.width, + owner.promiseSegmentedControl.numberOfSegments + ) + + owner.promiseSegmentedControl.selectedUnderLineView.snp.updateConstraints { + $0.leading.equalToSuperview().offset((width / CGFloat(count)) * CGFloat(index)) + } + + owner.promisePageViewController.setViewControllers([ + owner.promiseViewControllerList[index] + ], direction: direction, animated: false) + } } @objc func didSegmentedControlIndexUpdated() { - // let condition = viewModel.currentPageIndex.value <= promiseSegmentedControl.selectedSegmentIndex - // let direction: UIPageViewController.NavigationDirection = condition ? .forward : .reverse - // let (width, count, selectedIndex) = ( - // promiseSegmentedControl.bounds.width, - // promiseSegmentedControl.numberOfSegments, - // promiseSegmentedControl.selectedSegmentIndex - // ) - // - // promiseSegmentedControl.selectedUnderLineView.snp.updateConstraints { - // $0.leading.equalToSuperview().offset((width / CGFloat(count)) * CGFloat(selectedIndex)) - // } - // - // viewModel.segmentIndexDidChange( - // index: promiseSegmentedControl.selectedSegmentIndex - // ) - // - // promisePageViewController.setViewControllers([ - // promiseViewControllerList[viewModel.currentPageIndex.value] - // ], direction: direction, animated: false) + viewModel.pageControlDirection = viewModel.currentPageIndex.value <= promiseSegmentedControl.selectedSegmentIndex + viewModel.currentPageIndex.value = promiseSegmentedControl.selectedSegmentIndex } @objc diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 1bd41782..7d913dfb 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -13,6 +13,7 @@ class PromiseViewModel { // MARK: Property let promiseID: Int + let currentPageIndex = ObservablePattern(0) let promiseInfo = ObservablePattern(nil) let isPastDue = ObservablePattern(nil) let penalty = ObservablePattern(nil) @@ -20,6 +21,8 @@ class PromiseViewModel { let participantList = ObservablePattern<[Participant]>([]) let tardyList = ObservablePattern<[Comer]>([]) + var pageControlDirection = false + private let service: PromiseServiceProtocol From b00d4450a1ae6ea43e52429a8ad84d0612d30186 Mon Sep 17 00:00:00 2001 From: youz2me Date: Tue, 17 Sep 2024 00:13:07 +0900 Subject: [PATCH 13/28] =?UTF-8?q?fix/#388=20=EC=A7=80=EA=B0=81=EA=BE=B8?= =?UTF-8?q?=EB=AC=BC=EC=9D=B4=20=EB=B7=B0=20=EC=A0=9C=EC=95=BD=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum/Source/Promise/Tardy/View/TardyView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift b/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift index edf6b8f7..4c7ed846 100644 --- a/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift +++ b/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift @@ -42,7 +42,7 @@ class TardyView: BaseView { $0.backgroundColor = .maincolor } - private let titleLabel: UILabel = UILabel().then { + let titleLabel: UILabel = UILabel().then { $0.setText("이번 약속의 지각 꾸물이는?", style: .head01, color: .gray8) } @@ -82,7 +82,7 @@ class TardyView: BaseView { } noTardyView.snp.makeConstraints { - $0.edges.equalTo(safeAreaLayoutGuide) + $0.edges.equalToSuperview() } finishMeetingButton.snp.makeConstraints { From 1d3a774bc17cb6450d4cac954c8d01a0c0b3c79e Mon Sep 17 00:00:00 2001 From: youz2me Date: Tue, 17 Sep 2024 02:23:32 +0900 Subject: [PATCH 14/28] =?UTF-8?q?fix/#388=20=EC=95=BD=EC=86=8D=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EB=B7=B0=20=EC=95=BD=EC=86=8D=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=20=EC=9D=B8=EC=9B=90=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=83=89?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EC=95=88=EB=90=98=EB=8A=94=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseInfo/View/PromiseInfoView.swift | 15 ++++++++--- .../PromiseInfoViewController.swift | 26 +++++++++++-------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift b/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift index 023ad792..c66ec431 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/View/PromiseInfoView.swift @@ -28,9 +28,12 @@ class PromiseInfoView: BaseView { $0.backgroundColor = .white } + let participantLabel: UILabel = UILabel().then { + $0.setText("약속 참여 인원", style: .body05, color: .maincolor) + } + let participantNumberLabel: UILabel = UILabel().then { - $0.setText("약속 참여 인원 n명", style: .body05, color: .maincolor) - $0.setHighlightText("n명", style: .body05, color: .gray3) + $0.setText("n명", style: .body05, color: .gray3) } let participantCollectionView: UICollectionView = UICollectionView( @@ -117,6 +120,7 @@ class PromiseInfoView: BaseView { ) backgroundView.addSubviews( + participantLabel, participantNumberLabel, participantCollectionView, locationInfoLabel, @@ -165,11 +169,16 @@ class PromiseInfoView: BaseView { $0.bottom.equalToSuperview() } - participantNumberLabel.snp.makeConstraints { + participantLabel.snp.makeConstraints { $0.top.equalToSuperview().offset(18) $0.leading.equalToSuperview().offset(20) } + participantNumberLabel.snp.makeConstraints { + $0.centerY.equalTo(participantLabel) + $0.leading.equalTo(participantLabel.snp.trailing).offset(4) + } + participantCollectionView.snp.makeConstraints { $0.top.equalTo(participantNumberLabel.snp.bottom).offset(8.5) $0.horizontalEdges.equalToSuperview() diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 3316efa2..6b8ea0b3 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -85,6 +85,11 @@ extension PromiseInfoViewController { owner.rootView.timeContentLabel.setText(info.time, style: .body04) } + viewModel.participantList.bindOnMain(with: self) { owner, list in + owner.rootView.participantNumberLabel.setText("\(list.count)명", style: .body05, color: .gray3) + owner.rootView.participantCollectionView.reloadData() + } + viewModel.dDay.bindOnMain(with: self) { owner, dDay in guard let dDay else { return } @@ -94,22 +99,21 @@ extension PromiseInfoViewController { case 0: owner.rootView.dDayLabel.setText("D-DAY", style: .body05, color: .mainorange) case ..<0: - owner.rootView.dDayLabel.setText("D+\(-dDay)", style: .body05, color: .gray4) - owner.rootView.promiseImageView.image = .imgPromiseGray - owner.rootView.promiseNameLabel.textColor = .gray4 - owner.rootView.locationInfoLabel.textColor = .gray4 - owner.rootView.timeInfoLabel.textColor = .gray4 - owner.rootView.readyLevelInfoLabel.textColor = .gray4 - owner.rootView.penaltyLevelInfoLabel.textColor = .gray4 + owner.rootView.do { + $0.dDayLabel.setText("D+\(-dDay)", style: .body05, color: .gray4) + $0.promiseImageView.image = .imgPromiseGray + $0.participantLabel.textColor = .gray4 + $0.promiseNameLabel.textColor = .gray4 + $0.locationInfoLabel.textColor = .gray4 + $0.timeInfoLabel.textColor = .gray4 + $0.readyLevelInfoLabel.textColor = .gray4 + $0.penaltyLevelInfoLabel.textColor = .gray4 + } default: break } } - viewModel.participantList.bindOnMain(with: self) { owner, _ in - owner.rootView.participantCollectionView.reloadData() - } - viewModel.isPastDue.bindOnMain(with: self) { owner, _ in owner.rootView.editButton.isHidden = owner.viewModel.isEditButtonHidden() } From 5374f6ffe7d14f0ccf8103c844494cb0391d598e Mon Sep 17 00:00:00 2001 From: youz2me Date: Tue, 17 Sep 2024 02:25:32 +0900 Subject: [PATCH 15/28] =?UTF-8?q?refactor/#388=20=EC=A7=80=EA=B0=81=20?= =?UTF-8?q?=EA=BE=B8=EB=AC=BC=EC=9D=B4=20=EB=B7=B0=20=EB=B6=84=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PromiseViewController.swift | 25 +++++- .../Source/Promise/Tardy/View/TardyView.swift | 4 +- .../ViewController/TardyViewController.swift | 79 ++++++++++++++++++- .../Promise/ViewModel/PromiseViewModel.swift | 32 ++++++++ 4 files changed, 134 insertions(+), 6 deletions(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 901a206e..0b34c015 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -87,8 +87,7 @@ class PromiseViewController: BaseViewController { promiseSegmentedControl.snp.makeConstraints { $0.top.equalTo(view.safeAreaLayoutGuide) $0.leading.trailing.equalToSuperview().inset(-6) - $0.height.equalTo(Screen.height(60) - ) + $0.height.equalTo(Screen.height(60)) } promisePageViewController.view.snp.makeConstraints { @@ -164,6 +163,26 @@ private extension PromiseViewController { owner.promiseViewControllerList[index] ], direction: direction, animated: false) } + + viewModel.isFinishSuccess.bindOnMain(with: self) { owner, isSuccess in + guard let isSuccess = isSuccess else { return } + + if isSuccess { + self.navigationController?.popViewController(animated: true) + + if let viewController = self.navigationController?.viewControllers.last { + let toast = Toast() + toast.show(message: "약속 마치기 성공!", view: viewController.view, position: .bottom, inset: 100) + } + } + } + + viewModel.errorMessage.bindOnMain(with: self) { owner, message in + let toast = Toast() + guard let message = message else { return } + + toast.show(message: message, view: owner.view, position: .bottom, inset: 100) + } } @objc @@ -174,7 +193,7 @@ private extension PromiseViewController { @objc func finishMeetingButtonDidTap() { - + viewModel.updatePromiseCompletion() } @objc diff --git a/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift b/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift index 4c7ed846..8c20583b 100644 --- a/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift +++ b/KkuMulKum/Source/Promise/Tardy/View/TardyView.swift @@ -53,12 +53,12 @@ class TardyView: BaseView { backgroundColor = .white addSubviews( - tardyPenaltyView, titleLabel, tardyEmptyView, noTardyView, tardyCollectionView, - finishMeetingButton + finishMeetingButton, + tardyPenaltyView ) } diff --git a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift index cdcb74c6..e484c278 100644 --- a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift +++ b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift @@ -57,7 +57,77 @@ class TardyViewController: BaseViewController { private extension TardyViewController { func setupBinding() { + viewModel.penalty.bindOnMain(with: self) { owner, penalty in + owner.rootView.tardyPenaltyView.contentLabel.text = penalty + } + + viewModel.isPastDue.bindOnMain(with: self) { owner, isPastDue in + switch owner.viewModel.showTardyScreen() { + case .tardyEmptyView: + owner.rootView.do { + $0.finishMeetingButton.isEnabled = false + $0.tardyEmptyView.isHidden = false + $0.titleLabel.isHidden = false + $0.tardyPenaltyView.isHidden = false + $0.noTardyView.isHidden = true + $0.tardyCollectionView.isHidden = true + } + case .tardyListView: + owner.rootView.do { + $0.finishMeetingButton.isEnabled = true + $0.titleLabel.isHidden = false + $0.tardyPenaltyView.isHidden = false + $0.tardyCollectionView.isHidden = false + $0.tardyEmptyView.isHidden = true + $0.noTardyView.isHidden = true + + owner.rootView.tardyCollectionView.reloadData() + } + case .noTardyView: + owner.rootView.do { + $0.finishMeetingButton.isEnabled = true + $0.noTardyView.isHidden = false + $0.tardyEmptyView.isHidden = true + $0.titleLabel.isHidden = true + $0.tardyPenaltyView.isHidden = true + $0.tardyCollectionView.isHidden = true + } + } + } + viewModel.tardyList.bindOnMain(with: self) { owner, tardyList in + switch owner.viewModel.showTardyScreen() { + case .tardyEmptyView: + owner.rootView.do { + $0.finishMeetingButton.isEnabled = false + $0.tardyEmptyView.isHidden = false + $0.titleLabel.isHidden = false + $0.tardyPenaltyView.isHidden = false + $0.noTardyView.isHidden = true + $0.tardyCollectionView.isHidden = true + } + case .tardyListView: + owner.rootView.do { + $0.finishMeetingButton.isEnabled = true + $0.titleLabel.isHidden = false + $0.tardyPenaltyView.isHidden = false + $0.tardyCollectionView.isHidden = false + $0.tardyEmptyView.isHidden = true + $0.noTardyView.isHidden = true + + owner.rootView.tardyCollectionView.reloadData() + } + case .noTardyView: + owner.rootView.do { + $0.finishMeetingButton.isEnabled = true + $0.noTardyView.isHidden = false + $0.tardyEmptyView.isHidden = true + $0.titleLabel.isHidden = true + $0.tardyPenaltyView.isHidden = true + $0.tardyCollectionView.isHidden = true + } + } + } } } @@ -68,7 +138,7 @@ extension TardyViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - return 0 + return viewModel.tardyList.value.count } func collectionView( @@ -82,6 +152,13 @@ extension TardyViewController: UICollectionViewDataSource { return UICollectionViewCell() } + guard let tardyName = viewModel.tardyList.value[indexPath.row].name else { + return cell + } + + cell.nameLabel.setText(tardyName, style: .body06, color: .gray6) + cell.profileImageView.kf.setImage(with: URL(string: viewModel.tardyList.value[indexPath.row].profileImageURL ?? ""), placeholder: UIImage.imgProfile) + return cell } } diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 7d913dfb..30852d25 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -7,6 +7,12 @@ import Foundation +enum TardyScreen { + case tardyEmptyView + case tardyListView + case noTardyView +} + class PromiseViewModel { @@ -21,6 +27,9 @@ class PromiseViewModel { let participantList = ObservablePattern<[Participant]>([]) let tardyList = ObservablePattern<[Comer]>([]) + let isFinishSuccess = ObservablePattern(nil) + let errorMessage = ObservablePattern(nil) + var pageControlDirection = false private let service: PromiseServiceProtocol @@ -66,6 +75,23 @@ extension PromiseViewModel { return !(isParticipant && !isPastDue) } + func showTardyScreen() -> TardyScreen { + guard let isPastDue = isPastDue.value else { return .tardyEmptyView } + let hasTardy = !tardyList.value.isEmpty + + if !isPastDue { + return .tardyEmptyView + } + else if isPastDue && hasTardy { + return .tardyListView + } + else if isPastDue && !hasTardy { + return .noTardyView + } + + return .tardyEmptyView + } + /// 약속 상세 정보 조회 API 구현 함수 func fetchPromiseInfo() { Task { @@ -224,9 +250,15 @@ extension PromiseViewModel { guard let success = result?.success, success == true else { + guard let message = result?.error?.message else { return } + + errorMessage.value = message + print(">>>>> \(String(describing: result)) : \(#function)") return } + + isFinishSuccess.value = success } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } From eb7bd24e91ea68d57bfd0ebf829e6cf474e1f554 Mon Sep 17 00:00:00 2001 From: youz2me Date: Tue, 17 Sep 2024 02:32:25 +0900 Subject: [PATCH 16/28] =?UTF-8?q?fix/#388=20=EC=95=BD=EC=86=8D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=ED=99=94=EB=A9=B4=20=EB=A1=9C=EC=A7=81=20=EB=B0=94?= =?UTF-8?q?=EB=A1=9C=20=EB=84=98=EC=96=B4=EA=B0=80=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChooseContentViewController.swift | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift b/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift index a11b161f..70a9c772 100644 --- a/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift +++ b/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift @@ -106,12 +106,14 @@ private extension ChooseContentViewController { }) viewModel.isSuccess.bindOnMain(with: self) { owner, success in - let viewController = AddPromiseCompleteViewController(promiseID: self.viewModel.promiseID) - - viewController.setupNavigationBarTitle(with: "약속 수정하기") - viewController.rootView.titleLabel.text = "약속이 수정되었어요!" - - self.navigationController?.pushViewController(viewController, animated: true) + if success { + let viewController = AddPromiseCompleteViewController(promiseID: self.viewModel.promiseID) + + viewController.setupNavigationBarTitle(with: "약속 수정하기") + viewController.rootView.titleLabel.text = "약속이 수정되었어요!" + + self.navigationController?.pushViewController(viewController, animated: true) + } } } From e8e34b8ed4d48ec84aaee9a8fd20b7d0930cfa38 Mon Sep 17 00:00:00 2001 From: youz2me Date: Tue, 17 Sep 2024 20:37:13 +0900 Subject: [PATCH 17/28] =?UTF-8?q?fix/#388=20=EC=95=BD=EC=86=8D=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EB=B7=B0=20=EC=8B=9C=EA=B0=84=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=95=88=20=EB=9C=A8=EB=8A=94=20=EB=AC=B8=EC=A0=9C?= =?UTF-8?q?=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/PromiseInfoViewController.swift | 3 ++- .../Source/Promise/ViewModel/PromiseViewModel.swift | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift index 6b8ea0b3..db107ae6 100644 --- a/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift +++ b/KkuMulKum/Source/Promise/PromiseInfo/ViewController/PromiseInfoViewController.swift @@ -76,13 +76,14 @@ extension PromiseInfoViewController { func setupBinding() { viewModel.promiseInfo.bindOnMain(with: self) { owner, info in guard let info else { return } + let time = owner.viewModel.convertTime() owner.rootView.editButton.isHidden = owner.viewModel.isEditButtonHidden() owner.rootView.promiseNameLabel.setText(info.promiseName, style: .body01) owner.rootView.locationContentLabel.setText(info.placeName, style: .body04) owner.rootView.readyLevelContentLabel.setText(info.dressUpLevel, style: .body04) owner.rootView.penaltyLevelContentLabel.setText(info.penalty, style: .body04) - owner.rootView.timeContentLabel.setText(info.time, style: .body04) + owner.rootView.timeContentLabel.setText(time, style: .body04) } viewModel.participantList.bindOnMain(with: self) { owner, list in diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index 30852d25..e163f61b 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -92,6 +92,19 @@ extension PromiseViewModel { return .tardyEmptyView } + func convertTime() -> String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + + guard let promiseTime = promiseInfo.value?.time else { return "" } + guard let promiseDate = dateFormatter.date(from: promiseTime) else { return promiseTime } + + let timeFormatter = DateFormatter() + timeFormatter.dateFormat = "M월 d일 a H:mm" + + return timeFormatter.string(from: promiseDate) + } + /// 약속 상세 정보 조회 API 구현 함수 func fetchPromiseInfo() { Task { From 3c9b8bf1f677e953f099cc05b7b924869f147ad2 Mon Sep 17 00:00:00 2001 From: youz2me Date: Wed, 18 Sep 2024 17:37:43 +0900 Subject: [PATCH 18/28] =?UTF-8?q?fix/#388=20=EC=A4=80=EB=B9=84=20=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=EB=B7=B0=20=EC=A4=80=EB=B9=84=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?,=20=EC=9A=B0=EB=A6=AC=EB=93=A4=EC=9D=98=20=EC=A4=80=EB=B9=84?= =?UTF-8?q?=20=ED=98=84=ED=99=A9=20=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20=EB=B0=8F=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=94=EC=9D=B8?= =?UTF-8?q?=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyStatus/View/ReadyPlanInfoView.swift | 8 +- .../ReadyStatusViewController.swift | 97 ++++++++++++++++++- .../Promise/ViewModel/PromiseViewModel.swift | 44 ++++++++- 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift index 914ffe01..294a39c4 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyPlanInfoView.swift @@ -13,16 +13,16 @@ class ReadyPlanInfoView: BaseView { // MARK: Property let readyTimeLabel: UILabel = UILabel().then { - $0.setText("12시 30분에 준비하고,\n1시에 이동을 시작해야 해요", style: .body03) - $0.setHighlightText("12시 30분", "1시", style: .body03, color: .maincolor) + $0.setText("--시 --분에 준비하고,\n-시에 이동을 시작해야 해요", style: .body03) + $0.setHighlightText("--시 --분", "-시", style: .body03, color: .maincolor) } let requestReadyTimeLabel: UILabel = UILabel().then { - $0.setText("준비 소요 시간: 30분", style: .label02, color: .gray8) + $0.setText("준비 소요 시간: --분", style: .label02, color: .gray8) } let requestMoveTimeLabel: UILabel = UILabel().then { - $0.setText("이동 소요 시간: 1시간 30분", style: .label02, color: .gray8) + $0.setText("이동 소요 시간: --분", style: .label02, color: .gray8) } let editButton: UIButton = UIButton().then { diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index bd5c14f4..ba8ebb5b 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -44,6 +44,11 @@ class ReadyStatusViewController: BaseViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + + viewModel.fetchTardyInfo() + viewModel.fetchPromiseInfo() + viewModel.fetchMyReadyStatus() + viewModel.fetchPromiseParticipantList() } override func viewDidLayoutSubviews() { @@ -93,7 +98,41 @@ class ReadyStatusViewController: BaseViewController { extension ReadyStatusViewController { func setupBinding() { + viewModel.participantList.bindOnMain(with: self) { owner, _ in + owner.rootView.ourReadyStatusCollectionView.reloadData() + } + + viewModel.isPastDue.bindOnMain(with: self) { owner, isPastDue in + guard let isPastDue else { return } + + owner.rootView.readyPlanInfoView.editButton.isHidden = isPastDue + } + + viewModel.promiseInfo.bindOnMain(with: self) { owner, info in + guard let promiseInfo = info else { return } + + owner.rootView.do { + $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() + $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden + $0.enterReadyButtonView.isUserInteractionEnabled = promiseInfo.isParticipant + } + } + viewModel.myReadyInfo.bindOnMain(with: self) { owner, status in + owner.rootView.do { + $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() + $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden + } + } + + viewModel.requestReadyTime.bindOnMain(with: self) { owner, time in + owner.rootView.do { + $0.readyPlanInfoView.readyTimeLabel.setText("\(time[0])에 준비하고,\n\(time[1])에 이동을 시작해야 해요", style: .body03) + $0.readyPlanInfoView.readyTimeLabel.setHighlightText("\(time[0])","\(time[1])", style: .body03, color: .maincolor) + $0.readyPlanInfoView.requestReadyTimeLabel.setText("준비 소요 시간: \(time[2])", style: .label02, color: .gray8) + $0.readyPlanInfoView.requestMoveTimeLabel.setText("이동 소요 시간: \(time[3])", style: .label02, color: .gray8) + } + } } @objc @@ -113,12 +152,47 @@ extension ReadyStatusViewController { @objc func editReadyButtonDidTap() { + guard let promiseName = viewModel.promiseInfo.value?.promiseName, + let promiseTime = viewModel.myReadyInfo.value?.promiseTime, + let preparationTime = viewModel.myReadyInfo.value?.preparationTime, + let travelTime = viewModel.myReadyInfo.value?.travelTime else { + return + } + + let viewModel = SetReadyInfoViewModel( + promiseID: viewModel.promiseID, + promiseTime: promiseTime, + promiseName: promiseName, + service: PromiseService() + ) + viewModel.storedReadyHour = preparationTime / 60 + viewModel.storedReadyMinute = preparationTime % 60 + viewModel.storedMoveHour = travelTime / 60 + viewModel.storedMoveMinute = travelTime % 60 + + let viewController = SetReadyInfoViewController(viewModel: viewModel) + + navigationController?.pushViewController(viewController, animated: true) } @objc func enterReadyButtonDidTap() { + guard let promiseName = viewModel.promiseInfo.value?.promiseName, + let readyInfo = viewModel.myReadyInfo.value else { + return + } + + let viewController = SetReadyInfoViewController( + viewModel: SetReadyInfoViewModel( + promiseID: viewModel.promiseID, + promiseTime: readyInfo.promiseTime, + promiseName: promiseName, + service: PromiseService() + ) + ) + navigationController?.pushViewController(viewController, animated: true) } } @@ -130,7 +204,7 @@ extension ReadyStatusViewController: UICollectionViewDataSource { _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { - return 0 + return viewModel.participantList.value.count } func collectionView( @@ -145,6 +219,27 @@ extension ReadyStatusViewController: UICollectionViewDataSource { return UICollectionViewCell() } + let info = viewModel.participantList.value[indexPath.row] + + switch info.state { + case "꾸물중": + cell.readyStatusButton.setupButton("꾸물중", .none) + case "준비중": + cell.readyStatusButton.setupButton("준비중", .ready) + case "이동중": + cell.readyStatusButton.setupButton("이동중", .move) + case "도착": + cell.readyStatusButton.setupButton("도착", .done) + default: + break + } + + cell.nameLabel.text = info.name + cell.profileImageView.kf.setImage( + with: URL(string: info.profileImageURL ?? ""), + placeholder: UIImage.imgProfile + ) + return cell } } diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index e163f61b..ef718831 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -21,12 +21,13 @@ class PromiseViewModel { let promiseID: Int let currentPageIndex = ObservablePattern(0) let promiseInfo = ObservablePattern(nil) + let myReadyInfo = ObservablePattern(nil) let isPastDue = ObservablePattern(nil) let penalty = ObservablePattern(nil) let dDay = ObservablePattern(nil) + let requestReadyTime = ObservablePattern<[String]>(["", "", "", ""]) let participantList = ObservablePattern<[Participant]>([]) let tardyList = ObservablePattern<[Comer]>([]) - let isFinishSuccess = ObservablePattern(nil) let errorMessage = ObservablePattern(nil) @@ -62,6 +63,33 @@ private extension PromiseViewModel { dDay.value = components.day } + + func calculateReadyInfo() { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + + let timeFormatter = DateFormatter() + timeFormatter.dateFormat = "HH시 mm분" + + guard let promiseTime = myReadyInfo.value?.promiseTime, + let promiseDate = dateFormatter.date(from: promiseTime), + let preparationTime = myReadyInfo.value?.preparationTime, + let travelTime = myReadyInfo.value?.travelTime else { + return + } + + let readyStartTime = promiseDate.addingTimeInterval(-TimeInterval(preparationTime + travelTime + 10) * 60) + let moveStartTime = promiseDate.addingTimeInterval(-TimeInterval(travelTime + 10) * 60) + let preparationHours = preparationTime / 60 + let preparationMinutes = preparationTime % 60 + let travelHours = travelTime / 60 + let travelMinutes = travelTime % 60 + + requestReadyTime.value[0] = timeFormatter.string(from: readyStartTime) + requestReadyTime.value[1] = timeFormatter.string(from: moveStartTime) + requestReadyTime.value[2] = preparationHours == 0 ? "\(preparationMinutes)분" : "\(preparationHours)시간 \(preparationMinutes)분" + requestReadyTime.value[3] = travelHours == 0 ? "\(travelMinutes)분" : "\(travelHours)시간 \(travelMinutes)분" + } } extension PromiseViewModel { @@ -75,6 +103,16 @@ extension PromiseViewModel { return !(isParticipant && !isPastDue) } + func isReadyInfoEntered() -> Bool { + guard let isParticipant = promiseInfo.value?.isParticipant, + let _ = myReadyInfo.value?.preparationTime, + let _ = myReadyInfo.value?.travelTime else { + return false + } + + return isParticipant + } + func showTardyScreen() -> TardyScreen { guard let isPastDue = isPastDue.value else { return .tardyEmptyView } let hasTardy = !tardyList.value.isEmpty @@ -164,6 +202,10 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + myReadyInfo.value = result?.data + + calculateReadyInfo() } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } From 73833a3c4588d6124b2a7e0df72eeeadf8b7d77d Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 00:33:57 +0900 Subject: [PATCH 19/28] =?UTF-8?q?fix/#388=20=EC=A4=80=EB=B9=84=20=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=EB=B0=94=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OurReadyStatusCollectionViewCell.swift | 6 ++ .../ReadyStatus/View/ReadyStatusButton.swift | 6 +- .../ReadyStatusViewController.swift | 78 ++++++++++++++++++- .../Promise/ViewModel/PromiseViewModel.swift | 27 +++++++ 4 files changed, 110 insertions(+), 7 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/Cell/OurReadyStatusCollectionViewCell.swift b/KkuMulKum/Source/Promise/ReadyStatus/Cell/OurReadyStatusCollectionViewCell.swift index 72609de5..9b924423 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/Cell/OurReadyStatusCollectionViewCell.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/Cell/OurReadyStatusCollectionViewCell.swift @@ -26,6 +26,12 @@ class OurReadyStatusCollectionViewCell: BaseCollectionViewCell { $0.layer.borderWidth = 0.5 } + override func prepareForReuse() { + super.prepareForReuse() + + profileImageView.image = nil + } + override func setupView() { backgroundColor = .gray0 layer.cornerRadius = Screen.height(8) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift index 28cbf2c1..716de784 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusButton.swift @@ -7,7 +7,7 @@ import UIKit -enum ReadyProgressStatus { +enum ReadyStatus { case none case ready case move @@ -19,7 +19,7 @@ class ReadyStatusButton: UIButton { // MARK: - LifeCycle - init(title: String, readyStatus: ReadyProgressStatus) { + init(title: String, readyStatus: ReadyStatus) { super.init(frame: .zero) setupButton(title, readyStatus) @@ -37,7 +37,7 @@ class ReadyStatusButton: UIButton { extension ReadyStatusButton { func setupButton( _ title: String, - _ readyStatus: ReadyProgressStatus + _ readyStatus: ReadyStatus ) { switch readyStatus { case .none: diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index ba8ebb5b..97993620 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -110,11 +110,12 @@ extension ReadyStatusViewController { viewModel.promiseInfo.bindOnMain(with: self) { owner, info in guard let promiseInfo = info else { return } + let isParticipant = promiseInfo.isParticipant owner.rootView.do { $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden - $0.enterReadyButtonView.isUserInteractionEnabled = promiseInfo.isParticipant + $0.enterReadyButtonView.isUserInteractionEnabled = isParticipant } } @@ -125,6 +126,75 @@ extension ReadyStatusViewController { } } + viewModel.myReadyStatus.bindOnMain(with: self) { owner, state in + owner.rootView.myReadyStatusProgressView.do { + switch state { + case .none: + $0.readyStartButton.setupButton("준비 시작", .ready) + $0.moveStartButton.setupButton("이동 시작", .none) + $0.arrivalButton.setupButton("도착 완료", .none) + $0.readyStartButton.isEnabled = true + $0.moveStartButton.isEnabled = false + $0.arrivalButton.isEnabled = false + $0.readyStartTitleLabel.isHidden = false + $0.moveStartTitleLabel.isHidden = true + $0.arrivalTitleLabel.isHidden = true + $0.readyStartTimeLabel.isHidden = true + $0.moveStartTimeLabel.isHidden = true + $0.arrivalTimeLabel.isHidden = true + $0.statusProgressView.setProgress(0.0, animated: false) + case .ready: + $0.readyStartButton.setupButton("준비 중", .move) + $0.moveStartButton.setupButton("이동 시작", .ready) + $0.arrivalButton.setupButton("도착 완료", .none) + $0.readyStartButton.isEnabled = false + $0.moveStartButton.isEnabled = true + $0.arrivalButton.isEnabled = false + $0.readyStartTitleLabel.isHidden = true + $0.moveStartTitleLabel.isHidden = false + $0.arrivalTitleLabel.isHidden = true + $0.readyStartTimeLabel.isHidden = false + $0.moveStartTimeLabel.isHidden = true + $0.arrivalTimeLabel.isHidden = true + $0.readyStartCheckImageView.image = .iconCheck + $0.statusProgressView.setProgress(0.2, animated: false) + case .move: + $0.readyStartButton.setupButton("준비 완료", .done) + $0.moveStartButton.setupButton("이동 중", .move) + $0.arrivalButton.setupButton("도착 완료", .ready) + $0.readyStartButton.isEnabled = false + $0.moveStartButton.isEnabled = false + $0.arrivalButton.isEnabled = true + $0.readyStartTitleLabel.isHidden = true + $0.moveStartTitleLabel.isHidden = true + $0.arrivalTitleLabel.isHidden = false + $0.readyStartTimeLabel.isHidden = false + $0.moveStartTimeLabel.isHidden = false + $0.arrivalTimeLabel.isHidden = true + $0.readyStartCheckImageView.image = .iconCheck + $0.moveStartCheckImageView.image = .iconCheck + $0.statusProgressView.setProgress(0.5, animated: false) + case .done: + $0.readyStartButton.setupButton("준비 완료", .done) + $0.moveStartButton.setupButton("이동 완료", .done) + $0.arrivalButton.setupButton("도착 완료", .done) + $0.readyStartButton.isEnabled = false + $0.moveStartButton.isEnabled = false + $0.arrivalButton.isEnabled = false + $0.readyStartTitleLabel.isHidden = false + $0.moveStartTitleLabel.isHidden = false + $0.arrivalTitleLabel.isHidden = false + $0.readyStartTimeLabel.isHidden = false + $0.moveStartTimeLabel.isHidden = false + $0.arrivalTimeLabel.isHidden = false + $0.readyStartCheckImageView.image = .iconCheck + $0.moveStartCheckImageView.image = .iconCheck + $0.arrivalCheckImageView.image = .iconCheck + $0.statusProgressView.setProgress(1, animated: false) + } + } + } + viewModel.requestReadyTime.bindOnMain(with: self) { owner, time in owner.rootView.do { $0.readyPlanInfoView.readyTimeLabel.setText("\(time[0])에 준비하고,\n\(time[1])에 이동을 시작해야 해요", style: .body03) @@ -137,17 +207,17 @@ extension ReadyStatusViewController { @objc func readyStartButtonDidTap() { - + viewModel.updatePreparationStatus() } @objc func moveStartButtonDidTap() { - + viewModel.updateDepartureStatus() } @objc func arrivalButtonDidTap() { - + viewModel.updateArrivalStatus() } @objc diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index ef718831..f8fec745 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -22,6 +22,7 @@ class PromiseViewModel { let currentPageIndex = ObservablePattern(0) let promiseInfo = ObservablePattern(nil) let myReadyInfo = ObservablePattern(nil) + let myReadyStatus = ObservablePattern(.none) let isPastDue = ObservablePattern(nil) let penalty = ObservablePattern(nil) let dDay = ObservablePattern(nil) @@ -90,6 +91,22 @@ private extension PromiseViewModel { requestReadyTime.value[2] = preparationHours == 0 ? "\(preparationMinutes)분" : "\(preparationHours)시간 \(preparationMinutes)분" requestReadyTime.value[3] = travelHours == 0 ? "\(travelMinutes)분" : "\(travelHours)시간 \(travelMinutes)분" } + + func getMyReadyStatus() { + guard let info = myReadyInfo.value else { return } + switch (info.preparationStartAt, info.departureAt, info.arrivalAt) { + case (nil, nil, nil): + myReadyStatus.value = .none + case (.some, nil, nil): + myReadyStatus.value = .ready + case (.some, .some, nil): + myReadyStatus.value = .move + case (.some, .some, .some): + myReadyStatus.value = .done + default: + break + } + } } extension PromiseViewModel { @@ -206,6 +223,7 @@ extension PromiseViewModel { myReadyInfo.value = result?.data calculateReadyInfo() + getMyReadyStatus() } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } @@ -224,6 +242,9 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + fetchMyReadyStatus() + fetchPromiseParticipantList() } catch { print(">>>>> \(error.localizedDescription) : \(#function)") @@ -243,6 +264,9 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + fetchMyReadyStatus() + fetchPromiseParticipantList() } catch { print(">>>>> \(error.localizedDescription) : \(#function)") @@ -262,6 +286,9 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + fetchMyReadyStatus() + fetchPromiseParticipantList() } catch { print(">>>>> \(error.localizedDescription) : \(#function)") From 8ff8bd2629777c3113c7fa1b65a8376156a73514 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 00:57:02 +0900 Subject: [PATCH 20/28] =?UTF-8?q?fix/#388=20Observable=20Pattern=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ObservablePattern/ObservablePattern.swift | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/KkuMulKum/Resource/ObservablePattern/ObservablePattern.swift b/KkuMulKum/Resource/ObservablePattern/ObservablePattern.swift index a6829897..05cbed39 100644 --- a/KkuMulKum/Resource/ObservablePattern/ObservablePattern.swift +++ b/KkuMulKum/Resource/ObservablePattern/ObservablePattern.swift @@ -30,8 +30,6 @@ class ObservablePattern { func bind(_ listener: @escaping (T) -> Void) { listeners.append(listener) - - listener(value) } func bind(with object: Object, _ listener: @escaping (Object, T) -> Void) { @@ -39,8 +37,6 @@ class ObservablePattern { guard let object else { return } listener(object, value) } - - listener(object, value) } func bindOnMain(_ listener: @escaping (T) -> Void) { @@ -49,10 +45,6 @@ class ObservablePattern { listener(value) } } - - DispatchQueue.main.async { - listener(self.value) - } } func bindOnMain(with object: Object, _ listener: @escaping (Object, T) -> Void) { @@ -62,9 +54,5 @@ class ObservablePattern { listener(object, value) } } - - DispatchQueue.main.async { - listener(object, self.value) - } } } From 3b0adf5fae07ac7c249e93836d74ca0d6087ba2e Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 15:32:37 +0900 Subject: [PATCH 21/28] =?UTF-8?q?feat/#388=20=EC=A4=80=EB=B9=84=20?= =?UTF-8?q?=ED=98=84=ED=99=A9=20=EB=B0=94=EC=9D=B8=EB=94=A9=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/ReadyStatusProgressView.swift | 2 +- .../ReadyStatusViewController.swift | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusProgressView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusProgressView.swift index 5e436ba5..31c04b1b 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusProgressView.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/ReadyStatusProgressView.swift @@ -171,7 +171,7 @@ class ReadyStatusProgressView: BaseView { } arrivalCheckImageView.snp.makeConstraints { - $0.centerX.equalTo(arrivalTimeLabel) + $0.trailing.equalToSuperview().inset(53.5) $0.centerY.equalTo(readyStartCheckImageView) $0.height.equalTo(Screen.height(16)) $0.width.equalTo(arrivalCheckImageView.snp.height) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index 97993620..e33ed7d5 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -120,10 +120,19 @@ extension ReadyStatusViewController { } viewModel.myReadyInfo.bindOnMain(with: self) { owner, status in + let preparationStartAt = status?.preparationStartAt ?? " " + let departureAt = status?.departureAt ?? " " + let arrivalAt = status?.arrivalAt ?? " " + owner.rootView.do { + $0.myReadyStatusProgressView.readyStartTimeLabel.text = preparationStartAt + $0.myReadyStatusProgressView.moveStartTimeLabel.text = departureAt + $0.myReadyStatusProgressView.arrivalTimeLabel.text = arrivalAt $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden } + + } viewModel.myReadyStatus.bindOnMain(with: self) { owner, state in @@ -181,9 +190,9 @@ extension ReadyStatusViewController { $0.readyStartButton.isEnabled = false $0.moveStartButton.isEnabled = false $0.arrivalButton.isEnabled = false - $0.readyStartTitleLabel.isHidden = false - $0.moveStartTitleLabel.isHidden = false - $0.arrivalTitleLabel.isHidden = false + $0.readyStartTitleLabel.isHidden = true + $0.moveStartTitleLabel.isHidden = true + $0.arrivalTitleLabel.isHidden = true $0.readyStartTimeLabel.isHidden = false $0.moveStartTimeLabel.isHidden = false $0.arrivalTimeLabel.isHidden = false From 081b77cd2e0b3210ce10b91b2cf87912dd0959ae Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 15:33:07 +0900 Subject: [PATCH 22/28] =?UTF-8?q?fix/#388=20=EA=B0=9C=ED=96=89=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyStatus/ViewController/ReadyStatusViewController.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index e33ed7d5..747d5564 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -131,8 +131,6 @@ extension ReadyStatusViewController { $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden } - - } viewModel.myReadyStatus.bindOnMain(with: self) { owner, state in From 6fe41fd7bbe4aabf796f2475f255e020d643f0ae Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 15:56:25 +0900 Subject: [PATCH 23/28] =?UTF-8?q?fix/#388=20=EA=B0=80=EB=8F=85=EC=84=B1=20?= =?UTF-8?q?=EA=B3=A0=EB=A0=A4=ED=95=B4=EC=84=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/ReadyStatusViewController.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index 747d5564..ae05f9b1 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -124,10 +124,13 @@ extension ReadyStatusViewController { let departureAt = status?.departureAt ?? " " let arrivalAt = status?.arrivalAt ?? " " + owner.rootView.myReadyStatusProgressView.do { + $0.readyStartTimeLabel.text = preparationStartAt + $0.moveStartTimeLabel.text = departureAt + $0.arrivalTimeLabel.text = arrivalAt + } + owner.rootView.do { - $0.myReadyStatusProgressView.readyStartTimeLabel.text = preparationStartAt - $0.myReadyStatusProgressView.moveStartTimeLabel.text = departureAt - $0.myReadyStatusProgressView.arrivalTimeLabel.text = arrivalAt $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden } From f187bfbe061afe95b47105a3bd0e7d4aa7390222 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 16:17:17 +0900 Subject: [PATCH 24/28] =?UTF-8?q?fix/#388=20=EC=95=BD=EC=86=8D=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20=EB=B2=84=ED=8A=BC=20=EB=B3=B4=EC=9D=B4=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PagePromise/ViewController/PromiseViewController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 0b34c015..c0ccbaf4 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -144,7 +144,8 @@ private extension PromiseViewController { action: #selector(owner.moreButtonDidTap) ) - owner.navigationController?.navigationItem.rightBarButtonItem = info.isParticipant ? moreButton : nil + owner.navigationItem.rightBarButtonItem = info.isParticipant ? moreButton : nil + owner.removePromiseViewContoller.promiseNameLabel.text = info.promiseName owner.setupNavigationBarTitle(with: info.promiseName, isBorderHidden: true) } From 79b1f6c68b8258a8c34513d737bc339639ef04d2 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 16:36:02 +0900 Subject: [PATCH 25/28] =?UTF-8?q?feat/#388=20=EC=95=BD=EC=86=8D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20=EB=82=98=EA=B0=80=EA=B8=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=95=A1=EC=85=98=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EC=B0=B8=EC=97=AC=ED=95=98=EC=A7=80=20=EC=95=8A=EC=9D=80=20?= =?UTF-8?q?=EC=95=BD=EC=86=8D=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=EC=A4=80?= =?UTF-8?q?=EB=B9=84=20=ED=98=84=ED=99=A9=20=EB=B2=84=ED=8A=BC=20=EB=AA=BB?= =?UTF-8?q?=EB=88=84=EB=A5=B4=EA=B2=8C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/PromiseViewController.swift | 12 ++++++++++++ .../ViewController/ReadyStatusViewController.swift | 1 + .../Source/Promise/ViewModel/PromiseViewModel.swift | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index c0ccbaf4..41dd5ea5 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -184,6 +184,14 @@ private extension PromiseViewController { toast.show(message: message, view: owner.view, position: .bottom, inset: 100) } + + viewModel.isExitSuccess.bindOnMain(with: self) { owner, isSuccess in + owner.navigationController?.popViewController(animated: true) + } + + viewModel.isDeleteSuccess.bindOnMain(with: self) { owner, isSuccess in + owner.navigationController?.popViewController(animated: true) + } } @objc @@ -226,9 +234,13 @@ private extension PromiseViewController { extension PromiseViewController: CustomActionSheetDelegate { func actionButtonDidTap(for kind: ActionSheetKind) { if kind == .deletePromise { + viewModel.deletePromise() + dismiss(animated: false) } else { + viewModel.exitPromise() + dismiss(animated: false) } } diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift index ae05f9b1..61c2e4f5 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/ReadyStatusViewController.swift @@ -116,6 +116,7 @@ extension ReadyStatusViewController { $0.enterReadyButtonView.isHidden = owner.viewModel.isReadyInfoEntered() $0.readyPlanInfoView.isHidden = !$0.enterReadyButtonView.isHidden $0.enterReadyButtonView.isUserInteractionEnabled = isParticipant + $0.myReadyStatusProgressView.isUserInteractionEnabled = isParticipant } } diff --git a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift index f8fec745..06243eac 100644 --- a/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift +++ b/KkuMulKum/Source/Promise/ViewModel/PromiseViewModel.swift @@ -30,6 +30,8 @@ class PromiseViewModel { let participantList = ObservablePattern<[Participant]>([]) let tardyList = ObservablePattern<[Comer]>([]) let isFinishSuccess = ObservablePattern(nil) + let isDeleteSuccess = ObservablePattern(nil) + let isExitSuccess = ObservablePattern(nil) let errorMessage = ObservablePattern(nil) var pageControlDirection = false @@ -359,6 +361,8 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + isDeleteSuccess.value = success } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } @@ -377,6 +381,8 @@ extension PromiseViewModel { print(">>>>> \(String(describing: result)) : \(#function)") return } + + isExitSuccess.value = success } catch { print(">>>>> \(error.localizedDescription) : \(#function)") } From 370c27b63537589635685b9dd6ba2c2c6917dc95 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 20:44:24 +0900 Subject: [PATCH 26/28] =?UTF-8?q?fix/#388=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=83=81=ED=83=9C=20=EB=B3=80=ED=99=94=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreateMeetingViewController.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/KkuMulKum/Source/AddMeeting/CreateMeeting/ViewController/CreateMeetingViewController.swift b/KkuMulKum/Source/AddMeeting/CreateMeeting/ViewController/CreateMeetingViewController.swift index 41ac462d..44b18ae5 100644 --- a/KkuMulKum/Source/AddMeeting/CreateMeeting/ViewController/CreateMeetingViewController.swift +++ b/KkuMulKum/Source/AddMeeting/CreateMeeting/ViewController/CreateMeetingViewController.swift @@ -77,6 +77,10 @@ class CreateMeetingViewController: BaseViewController { ) ) } + + override func setupDelegate() { + rootView.nameTextField.delegate = self + } } @@ -91,8 +95,12 @@ private extension CreateMeetingViewController { switch state { case .valid: owner.rootView.presentButton.isEnabled = true + owner.rootView.nameTextField.layer.borderColor = UIColor.maincolor.cgColor + owner.rootView.characterLabel.textColor = .maincolor case .invalid: owner.rootView.errorLabel.isHidden = false + owner.rootView.nameTextField.layer.borderColor = UIColor.mainred.cgColor + owner.rootView.characterLabel.textColor = .mainred case .empty: break } @@ -178,3 +186,14 @@ private extension CreateMeetingViewController { } } } + +extension CreateMeetingViewController: UITextFieldDelegate { + func textFieldDidBeginEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.maincolor.cgColor + } + + func textFieldDidEndEditing(_ textField: UITextField) { + rootView.characterLabel.textColor = .gray3 + rootView.nameTextField.layer.borderColor = UIColor.gray3.cgColor + } +} From f52f7ad97c9c294783bc3bf4217d510a524f4559 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 20:53:51 +0900 Subject: [PATCH 27/28] =?UTF-8?q?fix/#388=20=ED=98=84=EC=9E=AC=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=EB=B3=B4=EB=8B=A4=20=EC=95=9E=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=AA=BB=EA=B0=80=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EditPromise/ViewController/EditPromiseViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KkuMulKum/Source/Promise/EditPromise/ViewController/EditPromiseViewController.swift b/KkuMulKum/Source/Promise/EditPromise/ViewController/EditPromiseViewController.swift index b3963e06..f8459509 100644 --- a/KkuMulKum/Source/Promise/EditPromise/ViewController/EditPromiseViewController.swift +++ b/KkuMulKum/Source/Promise/EditPromise/ViewController/EditPromiseViewController.swift @@ -116,7 +116,7 @@ private extension EditPromiseViewController { return } - rootView.datePicker.minimumDate = .none + rootView.datePicker.minimumDate = .now rootView.datePicker.date = date rootView.timePicker.date = date } From 8b8737567e329cba7b52e6cf26c995fdcbf9ed44 Mon Sep 17 00:00:00 2001 From: youz2me Date: Fri, 20 Sep 2024 21:58:17 +0900 Subject: [PATCH 28/28] =?UTF-8?q?fix/#388=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewController/ChooseContentViewController.swift | 2 +- .../ViewController/PromiseViewController.swift | 7 +++---- .../Tardy/ViewController/TardyViewController.swift | 9 ++++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift b/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift index 70a9c772..c0d0231a 100644 --- a/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift +++ b/KkuMulKum/Source/Promise/EditPromise/ViewController/ChooseContentViewController.swift @@ -107,7 +107,7 @@ private extension ChooseContentViewController { viewModel.isSuccess.bindOnMain(with: self) { owner, success in if success { - let viewController = AddPromiseCompleteViewController(promiseID: self.viewModel.promiseID) + let viewController = AddPromiseCompleteViewController(promiseID: owner.viewModel.promiseID) viewController.setupNavigationBarTitle(with: "약속 수정하기") viewController.rootView.titleLabel.text = "약속이 수정되었어요!" diff --git a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift index 41dd5ea5..c4f873b9 100644 --- a/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift +++ b/KkuMulKum/Source/Promise/PagePromise/ViewController/PromiseViewController.swift @@ -166,7 +166,7 @@ private extension PromiseViewController { } viewModel.isFinishSuccess.bindOnMain(with: self) { owner, isSuccess in - guard let isSuccess = isSuccess else { return } + guard let isSuccess else { return } if isSuccess { self.navigationController?.popViewController(animated: true) @@ -179,8 +179,8 @@ private extension PromiseViewController { } viewModel.errorMessage.bindOnMain(with: self) { owner, message in + guard let message else { return } let toast = Toast() - guard let message = message else { return } toast.show(message: message, view: owner.view, position: .bottom, inset: 100) } @@ -237,8 +237,7 @@ extension PromiseViewController: CustomActionSheetDelegate { viewModel.deletePromise() dismiss(animated: false) - } - else { + } else { viewModel.exitPromise() dismiss(animated: false) diff --git a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift index e484c278..3c3ce373 100644 --- a/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift +++ b/KkuMulKum/Source/Promise/Tardy/ViewController/TardyViewController.swift @@ -81,7 +81,7 @@ private extension TardyViewController { $0.tardyEmptyView.isHidden = true $0.noTardyView.isHidden = true - owner.rootView.tardyCollectionView.reloadData() + $0.tardyCollectionView.reloadData() } case .noTardyView: owner.rootView.do { @@ -115,7 +115,7 @@ private extension TardyViewController { $0.tardyEmptyView.isHidden = true $0.noTardyView.isHidden = true - owner.rootView.tardyCollectionView.reloadData() + $0.tardyCollectionView.reloadData() } case .noTardyView: owner.rootView.do { @@ -157,7 +157,10 @@ extension TardyViewController: UICollectionViewDataSource { } cell.nameLabel.setText(tardyName, style: .body06, color: .gray6) - cell.profileImageView.kf.setImage(with: URL(string: viewModel.tardyList.value[indexPath.row].profileImageURL ?? ""), placeholder: UIImage.imgProfile) + cell.profileImageView.kf.setImage( + with: URL(string: viewModel.tardyList.value[indexPath.row].profileImageURL ?? ""), + placeholder: UIImage.imgProfile + ) return cell }