diff --git a/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift b/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift index 40a4b9ed..b21a1a88 100644 --- a/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift +++ b/Projects/Presentation/Sources/Common/Component/RoutineCardView.swift @@ -235,13 +235,15 @@ final class RoutineCardView: UIView { } if let _ = routine as? Routine { - addSubview(editButton) addSubview(deleteButton) - editButton.snp.makeConstraints { make in - make.top.equalToSuperview().offset(Layout.plusButtonTopSpacing) - make.trailing.equalTo(deleteButton).offset(-Layout.editButtonTrailingSpacing) - make.size.equalTo(Layout.plusButtonSize) + if !routine.isDeleted { + addSubview(editButton) + editButton.snp.makeConstraints { make in + make.top.equalToSuperview().offset(Layout.plusButtonTopSpacing) + make.trailing.equalTo(deleteButton).offset(-Layout.editButtonTrailingSpacing) + make.size.equalTo(Layout.plusButtonSize) + } } deleteButton.snp.makeConstraints { make in diff --git a/Projects/Presentation/Sources/Common/Component/ToastView.swift b/Projects/Presentation/Sources/Common/Component/ToastView.swift index 584dbb69..ba9c8640 100644 --- a/Projects/Presentation/Sources/Common/Component/ToastView.swift +++ b/Projects/Presentation/Sources/Common/Component/ToastView.swift @@ -17,7 +17,7 @@ final class ToastView: UIView { private let checkIcon = UIImageView() private let messageLabel = UILabel() - private let message: String + private var message: String init(message: String) { self.message = message @@ -62,7 +62,12 @@ final class ToastView: UIView { } } - func showToastMessageView() { + func showToastMessageView(message: String? = nil) { + if let message { + self.message = message + self.messageLabel.text = message + } + alpha = 0 isHidden = false diff --git a/Projects/Presentation/Sources/Common/Extension/Notification+.swift b/Projects/Presentation/Sources/Common/Extension/Notification+.swift index 2afe4099..3df19b53 100644 --- a/Projects/Presentation/Sources/Common/Extension/Notification+.swift +++ b/Projects/Presentation/Sources/Common/Extension/Notification+.swift @@ -9,4 +9,5 @@ import Foundation extension Notification.Name { static let showRecommendedRoutineToast = Notification.Name("showRecommendedRoutineToast") + static let showDeletedRoutineToast = Notification.Name("showDeletedRoutineToast") } diff --git a/Projects/Presentation/Sources/Common/Protocol/RoutineProtocol.swift b/Projects/Presentation/Sources/Common/Protocol/RoutineProtocol.swift index b15996b8..659531c4 100644 --- a/Projects/Presentation/Sources/Common/Protocol/RoutineProtocol.swift +++ b/Projects/Presentation/Sources/Common/Protocol/RoutineProtocol.swift @@ -11,4 +11,5 @@ protocol RoutineProtocol { var title: String { get } var routineType: RoutineCategoryType? { get } var subRoutines: [String] { get } + var isDeleted: Bool { get } } diff --git a/Projects/Presentation/Sources/Onboarding/Model/RecommendedRoutine.swift b/Projects/Presentation/Sources/Onboarding/Model/RecommendedRoutine.swift index 73820344..f7a079d9 100644 --- a/Projects/Presentation/Sources/Onboarding/Model/RecommendedRoutine.swift +++ b/Projects/Presentation/Sources/Onboarding/Model/RecommendedRoutine.swift @@ -15,6 +15,7 @@ public struct RecommendedRoutine: BitnagilChoiceProtocol, RoutineProtocol, Hasha let routineCategory: RoutineCategoryType let routineType: RoutineCategoryType? let routineLevel: RoutineLevelType + let isDeleted: Bool init( id: Int, @@ -32,6 +33,7 @@ public struct RecommendedRoutine: BitnagilChoiceProtocol, RoutineProtocol, Hasha self.routineCategory = routineCategory self.routineType = routineType self.routineLevel = routineLevel + self.isDeleted = false } } diff --git a/Projects/Presentation/Sources/RoutineList/View/RoutineListViewController.swift b/Projects/Presentation/Sources/RoutineList/View/RoutineListViewController.swift index ab4189b5..36308b0c 100644 --- a/Projects/Presentation/Sources/RoutineList/View/RoutineListViewController.swift +++ b/Projects/Presentation/Sources/RoutineList/View/RoutineListViewController.swift @@ -20,6 +20,8 @@ final class RoutineListViewController: BaseViewController static let routineScrollViewTopSpacing: CGFloat = 16 static let routineStackViewSpacing: CGFloat = 12 static let routineStackViewBottomSpacing: CGFloat = 60 + static let toastMessageViewHeight: CGFloat = 52 + static let toastMessageViewBottomSpacing: CGFloat = 20 } private let weekView: WeekView @@ -27,6 +29,8 @@ final class RoutineListViewController: BaseViewController private let routineScrollView = UIScrollView() private let routineStackView = UIStackView() private var routineCardViews: [String: RoutineCardView] = [:] + private let deleteToastMessage: String = "삭제가 완료되었습니다." + private var toastMessageView = ToastView(message: "") private var dimmedView: UIView? private var cancellables: Set @@ -79,6 +83,7 @@ final class RoutineListViewController: BaseViewController view.addSubview(emptyView) view.addSubview(routineScrollView) routineScrollView.addSubview(routineStackView) + view.addSubview(toastMessageView) weekView.snp.makeConstraints { make in make.top.equalTo(safeArea).offset(Layout.weekViewTopSpacing) @@ -104,6 +109,13 @@ final class RoutineListViewController: BaseViewController make.bottom.equalToSuperview().inset(Layout.routineStackViewBottomSpacing) make.width.equalTo(routineScrollView.snp.width) } + + toastMessageView.snp.makeConstraints { make in + make.leading.equalTo(safeArea).offset(Layout.horizontalMargin) + make.trailing.equalTo(safeArea).inset(Layout.horizontalMargin) + make.height.equalTo(Layout.toastMessageViewHeight) + make.bottom.equalTo(safeArea).inset(Layout.toastMessageViewBottomSpacing) + } } override func bind() { @@ -129,6 +141,14 @@ final class RoutineListViewController: BaseViewController self?.updateRoutineStackView(routines: routines) } .store(in: &cancellables) + + NotificationCenter.default.publisher(for: .showDeletedRoutineToast) + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self else { return } + self.toastMessageView.showToastMessageView(message: deleteToastMessage) + } + .store(in: &cancellables) } private func updateRoutineStackView(routines: [Routine]) { @@ -222,7 +242,7 @@ extension RoutineListViewController: RoutineCardViewDelegate { view.addSubview(newDimmedView) dimmedView = newDimmedView - if routine.repeatDay.isEmpty { + if routine.repeatDay.isEmpty || routine.isDeleted { let routineDeleteAlertViewController = RoutineDeleteAlertViewController(viewModel: viewModel, isDeleteAllRoutines: false) if let sheet = routineDeleteAlertViewController.sheetPresentationController { sheet.prefersGrabberVisible = false diff --git a/Projects/Presentation/Sources/RoutineList/ViewModel/RoutineListViewModel.swift b/Projects/Presentation/Sources/RoutineList/ViewModel/RoutineListViewModel.swift index b90518e9..ae671a9c 100644 --- a/Projects/Presentation/Sources/RoutineList/ViewModel/RoutineListViewModel.swift +++ b/Projects/Presentation/Sources/RoutineList/ViewModel/RoutineListViewModel.swift @@ -73,6 +73,8 @@ final class RoutineListViewModel: ViewModel { let endDateString = endDate.convertToString(dateType: .yearMonthDate) let routinesDictionary = try await routineRepository.fetchRoutines(from: startDateString, to: endDateString) + + self.routines.removeAll() for dailyRoutine in routinesDictionary { let date = dailyRoutine.key let routine = dailyRoutine.value.routines.map({ $0.toRoutine() }) @@ -118,9 +120,19 @@ final class RoutineListViewModel: ViewModel { } deleteRoutineResultSubject.send(true) fetchRoutines() + showDeletedRoutineToastMessageView() } catch { deleteRoutineResultSubject.send(false) } } } + + private func showDeletedRoutineToastMessageView() { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { + NotificationCenter.default.post( + name: .showDeletedRoutineToast, + object: nil, + userInfo: nil) + } + } }