diff --git a/DE/DE/Sources/Core/CommonUI/Protocols/VintageSelectionViewModel.swift b/DE/DE/Sources/Core/CommonUI/Protocols/VintageSelectionViewModel.swift new file mode 100644 index 00000000..7c73f418 --- /dev/null +++ b/DE/DE/Sources/Core/CommonUI/Protocols/VintageSelectionViewModel.swift @@ -0,0 +1,17 @@ +// Copyright © 2025 DRINKIG. All rights reserved + +import Foundation + +public protocol VintageSelectionViewModel: AnyObject { + // 화면 상단에 표시될 제목 (e.g., 와인 이름) + var screenTitle: String { get } + + // 화면 상단에 표시될 설명 + var screenDescription: String { get } + + // 사용자가 선택한 빈티지를 저장하는 함수 + func save(vintage: Int) + + // '뒤로가기' 시 필요한 데이터 리셋 로직 + func handleBackButton() +} diff --git a/DE/DE/Sources/Features/Setting/Models/MyOwnedWine.swift b/DE/DE/Sources/Features/Setting/Models/MyOwnedWine.swift index 088d9704..4aa006f9 100644 --- a/DE/DE/Sources/Features/Setting/Models/MyOwnedWine.swift +++ b/DE/DE/Sources/Features/Setting/Models/MyOwnedWine.swift @@ -1,5 +1,6 @@ // Copyright © 2024 DRINKIG. All rights reserved +import CoreModule import UIKit public struct MyOwnedWine { @@ -132,6 +133,10 @@ public class MyOwnedWineManager { return wine.vintage } + func getOnlyWineName() -> String { + return wine.wineName + } + /// 와인 데이터를 초기화 public func resetWine() { wine = MyOwnedWine() @@ -141,3 +146,21 @@ public class MyOwnedWineManager { wine.vintage = nil } } + +extension MyOwnedWineManager: VintageSelectionViewModel { + public var screenTitle: String { + return getOnlyWineName() + } + + public var screenDescription: String { + return "빈티지를 선택해 주세요" + } + + public func save(vintage: Int) { + setVintage(vintage) + } + + public func handleBackButton() { + resetVintage() + } +} diff --git a/DE/DE/Sources/Features/Setting/ViewControllers/MyWine/AddNewWineViewController.swift b/DE/DE/Sources/Features/Setting/ViewControllers/MyWine/AddNewWineViewController.swift index 3259ef17..e620c6e0 100644 --- a/DE/DE/Sources/Features/Setting/ViewControllers/MyWine/AddNewWineViewController.swift +++ b/DE/DE/Sources/Features/Setting/ViewControllers/MyWine/AddNewWineViewController.swift @@ -15,6 +15,7 @@ public class AddNewWineViewController : UIViewController, UITextFieldDelegate, U var registerWine: MyOwnedWine = MyOwnedWine() let networkService = WineService() private let errorHandler = NetworkErrorHandler() + let wineManager = MyOwnedWineManager.shared var isLoading = false var currentPage = 0 @@ -190,12 +191,19 @@ public class AddNewWineViewController : UIViewController, UITextFieldDelegate, U logCellClick(screenName: screenName, indexPath: indexPath, cellName: Tracking.CellEvent.searchWineCellTapped, fileName: #file, cellID: "SearchResultTableViewCell") /// 다른 프로퍼티 초기화 후 진행 - MyOwnedWineManager.shared.resetWine() + wineManager.resetWine() - let vc = SelectVintageViewController() let selectedWine = wineResults[indexPath.row] - MyOwnedWineManager.shared.setWineId(selectedWine.wineId) - MyOwnedWineManager.shared.setWineName(selectedWine.name) + wineManager.setWineId(selectedWine.wineId) + wineManager.setWineName(selectedWine.name) + + let vc = ReusableVintageSelectionViewController(viewModel: wineManager) + + vc.onComplete = { [weak self] _ in + let nextVC = BuyNewWineDateViewController() + self?.navigationController?.pushViewController(nextVC, animated: true) + } + navigationController?.pushViewController(vc, animated: true) } diff --git a/DE/DE/Sources/Features/TastingNote/Models/TNWineDataManager.swift b/DE/DE/Sources/Features/TastingNote/Models/TNWineDataManager.swift index aa08933e..75bf6077 100644 --- a/DE/DE/Sources/Features/TastingNote/Models/TNWineDataManager.swift +++ b/DE/DE/Sources/Features/TastingNote/Models/TNWineDataManager.swift @@ -1,6 +1,7 @@ // Copyright © 2024 DRINKIG. All rights reserved import Foundation +import CoreModule class TNWineDataManager { // MARK: - Properties @@ -8,7 +9,7 @@ class TNWineDataManager { var wineId: Int var wineName: String - var vintage: Int + var vintage: Int? var sort: String var country: String var region: String @@ -19,7 +20,7 @@ class TNWineDataManager { public init( wineId: Int = 0, wineName: String = "", - vintage: Int = 0, + vintage: Int? = nil, sort: String = "", country: String = "", region: String = "", @@ -68,5 +69,36 @@ class TNWineDataManager { variety = "" } + func resetVintage() { + vintage = nil + } + + public func getDisplayName() -> String { + if let vintage = vintage { + return "\(wineName) \(vintage)" + } else { + return wineName + } + } } + +extension TNWineDataManager: VintageSelectionViewModel { + var screenTitle: String { + return self.wineName + } + + var screenDescription: String { + return "빈티지를 선택해 주세요" + } + + func save(vintage: Int) { + updateWineData(vintage: vintage) + } + + func handleBackButton() { + resetVintage() + } + + +} diff --git a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/ChooseWineColorViewController.swift b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/ChooseWineColorViewController.swift index 34daefa5..9bd7d01a 100644 --- a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/ChooseWineColorViewController.swift +++ b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/ChooseWineColorViewController.swift @@ -23,9 +23,8 @@ public class ChooseWineColorViewController: UIViewController, FirebaseTrackable public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - let fullName = "\(wineData.wineName) \(wineData.vintage)" - colorView.header.setTitleLabel(title: fullName) + + colorView.header.setTitleLabel(title: wineData.getDisplayName()) self.navigationController?.setNavigationBarHidden(false, animated: animated) colorView.infoView.image.sd_setImage(with: URL(string: wineData.imageUrl)) diff --git a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/NoseTestVC.swift b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/NoseTestVC.swift index 78d9d1e6..43ce101c 100644 --- a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/NoseTestVC.swift +++ b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/NoseTestVC.swift @@ -43,8 +43,7 @@ public class NoseTestVC: UIViewController, UIScrollViewDelegate, FirebaseTrackab } } - let fullName = "\(wineData.wineName) \(wineData.vintage)" - topView.header.setTitleLabel(title: fullName, + topView.header.setTitleLabel(title: wineData.getDisplayName(), titleStyle: AppTextStyle.KR.subtitle1, titleColor: AppColor.purple100, description: despText, diff --git a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RatingWineViewController.swift b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RatingWineViewController.swift index a93211c2..8d3b673b 100644 --- a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RatingWineViewController.swift +++ b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RatingWineViewController.swift @@ -27,10 +27,9 @@ public class RatingWineViewController: UIViewController, FirebaseTrackable { self.view.addSubview(indicator) self.navigationController?.setNavigationBarHidden(false, animated: animated) NotificationCenter.default.addObserver(self, selector: #selector(keyboardUp), name: UIResponder.keyboardWillShowNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(keyboardDown), name: UIResponder.keyboardWillHideNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDown), name: UIResponder.keyboardWillHideNotification, object: nil) - let fullName = "\(wineData.wineName) \(wineData.vintage)" - rView.header.setTitleLabel(title: fullName) + rView.header.setTitleLabel(title: wineData.getDisplayName()) rView.infoView.image.sd_setImage(with: URL(string: wineData.imageUrl)) rView.infoView.countryContents.text = wineData.country + ", " + wineData.region rView.infoView.kindContents.text = wineData.sort @@ -144,9 +143,11 @@ public class RatingWineViewController: UIViewController, FirebaseTrackable { } private func postCreateTastingNote() async throws { + guard let vintage = wineData.vintage else { return } + let createNoteDTO = networkService.makePostNoteDTO( wineId: wineData.wineId, - vintage: wineData.vintage, + vintage: vintage, color: tnManager.color, tasteDate: tnManager.tasteDate, sugarContent: tnManager.sugarContent, diff --git a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RecordGraphViewController.swift b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RecordGraphViewController.swift index 1a62c60e..7aca9362 100644 --- a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RecordGraphViewController.swift +++ b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/RecordGraphViewController.swift @@ -41,8 +41,7 @@ public class RecordGraphViewController: UIViewController, UIScrollViewDelegate, super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(false, animated: animated) recordGraphView.updateLabels() - let fullName = "\(wineData.wineName) \(wineData.vintage)" - header.setTitleLabel(title: fullName) + header.setTitleLabel(title: wineData.getDisplayName()) } public override func viewWillDisappear(_ animated: Bool) { diff --git a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/SearchWineViewController.swift b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/SearchWineViewController.swift index 2c4fb329..9ababebf 100644 --- a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/SearchWineViewController.swift +++ b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/SearchWineViewController.swift @@ -20,12 +20,12 @@ public class SearchWineViewController : UIViewController, UITableViewDelegate, U public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + self.navigationController?.isNavigationBarHidden = false self.view.addSubview(indicator) } public override func viewDidLoad() { super.viewDidLoad() - self.navigationController?.isNavigationBarHidden = false view.backgroundColor = AppColor.background self.view = searchHomeView searchHomeView.noSearchResultLabel.isHidden = true @@ -168,9 +168,17 @@ public class SearchWineViewController : UIViewController, UITableViewDelegate, U public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { logCellClick(screenName: screenName, indexPath: indexPath, cellName: Tracking.CellEvent.searchWineCellTapped, fileName: #file, cellID: "SearchResultTableViewCell") - let vc = TastedDateViewController() + TNWineDataManager.shared.updateWineData(wineId: wineResults[indexPath.row].wineId, wineName: wineResults[indexPath.row].name, sort: wineResults[indexPath.row].sort, country: wineResults[indexPath.row].country, region: wineResults[indexPath.row].region, imageUrl: wineResults[indexPath.row].imageUrl, variety: wineResults[indexPath.row].variety) - navigationController?.pushViewController(vc, animated: true) + + let selectVintageVC = ReusableVintageSelectionViewController(viewModel: TNWineDataManager.shared) + + selectVintageVC.onComplete = { [weak self] _ in + let vc = TastedDateViewController() + self?.navigationController?.pushViewController(vc, animated: true) + } + + navigationController?.pushViewController(selectVintageVC, animated: true) } public func scrollViewDidScroll(_ scrollView: UIScrollView) { diff --git a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/TastedDateViewController.swift b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/TastedDateViewController.swift index 484b583a..6e8cf86a 100644 --- a/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/TastedDateViewController.swift +++ b/DE/DE/Sources/Features/TastingNote/ViewControllers/CreateVCs/TastedDateViewController.swift @@ -20,8 +20,7 @@ public class TastedDateViewController: UIViewController, FirebaseTrackable { public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(false, animated: animated) - let fullName = "\(self.wineData.wineName) \(self.wineData.vintage)" - tastedDateView.topView.setTitleLabel(title: fullName, + tastedDateView.topView.setTitleLabel(title: wineData.getDisplayName(), titleStyle: AppTextStyle.KR.subtitle1, titleColor: AppColor.purple100, description: despText, diff --git a/DE/DE/Sources/Features/Setting/ViewControllers/MyWine/SelectVintageViewController.swift b/DE/DE/Sources/Features/Vintage/ReusableVintageSelectionViewController.swift similarity index 71% rename from DE/DE/Sources/Features/Setting/ViewControllers/MyWine/SelectVintageViewController.swift rename to DE/DE/Sources/Features/Vintage/ReusableVintageSelectionViewController.swift index 036bcca4..b51d3fbf 100644 --- a/DE/DE/Sources/Features/Setting/ViewControllers/MyWine/SelectVintageViewController.swift +++ b/DE/DE/Sources/Features/Vintage/ReusableVintageSelectionViewController.swift @@ -5,18 +5,28 @@ import CoreModule import DesignSystem import SnapKit import Then -// step 1. 빈티지 선택 - -final class SelectVintageViewController: UIViewController { +final class ReusableVintageSelectionViewController: UIViewController { let navigationBarManager = NavigationBarManager() let vintageView = MyWineVintageView() - let wineManager = MyOwnedWineManager.shared + private let viewModel: VintageSelectionViewModel + + public var onComplete: ((Int) -> Void)? + + init(viewModel: VintageSelectionViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - self.vintageView.setWineName(wineManager.getWineName()) + self.vintageView.setTopSection(name: viewModel.screenTitle, descText: viewModel.screenDescription) self.navigationController?.setNavigationBarHidden(false, animated: animated) } @@ -31,13 +41,13 @@ final class SelectVintageViewController: UIViewController { setupActions() setupNavigationBar() } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) -// logScreenView(fileName: #file) + // logScreenView(fileName: #file) } - - func setupUI() { + + private func setupUI() { view.backgroundColor = AppColor.background view.addSubview(vintageView) @@ -48,8 +58,8 @@ final class SelectVintageViewController: UIViewController { } } - func setupActions() { - vintageView.nextButton.addTarget(self, action: #selector(nextVC), for: .touchUpInside) + private func setupActions() { + vintageView.nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) vintageView.yearPicker.onYearSelected = { [weak self] year in self?.vintageView.nextButton.isEnabled(isEnabled: true) @@ -62,7 +72,7 @@ final class SelectVintageViewController: UIViewController { maxYear: vintageView.yearPicker.maxYear, selectedYear: vintageView.yearPicker.selectedYear ) - + modal.onYearConfirmed = { [weak self] selected in self?.vintageView.yearPicker.setSelectedYear(selected) self?.vintageView.nextButton.isEnabled = true @@ -70,7 +80,7 @@ final class SelectVintageViewController: UIViewController { } modal.modalPresentationStyle = .pageSheet - + if let sheet = modal.sheetPresentationController { sheet.detents = [.medium()] sheet.prefersGrabberVisible = true @@ -88,34 +98,34 @@ final class SelectVintageViewController: UIViewController { navigationBarManager.addBackButton( to: navigationItem, target: self, - action: #selector(prevVC) + action: #selector(backButtonTapped) ) } - @objc func prevVC() { - wineManager.resetVintage() + @objc func backButtonTapped() { + viewModel.handleBackButton() navigationController?.popViewController(animated: true) } - @objc func nextVC() { -// logButtonClick(screenName: screenName, buttonName: Tracking.ButtonEvent.nextBtnTapped, fileName: #file) + @objc func nextButtonTapped() { + // logButtonClick(screenName: screenName, buttonName: Tracking.ButtonEvent.nextBtnTapped, fileName: #file) + guard let selectedYear = vintageView.yearPicker.selectedYear else { - // 연도가 선택되지 않았을 경우: Alert 표시 등 showToastMessage(message: "연도가 선택되지 않았습니다.", yPosition: view.frame.height * 0.5) return } - // wineManager에 선택한 연도 저장 - wineManager.setVintage(selectedYear) - - // 다음 화면으로 이동 - let vc = BuyNewWineDateViewController() - navigationController?.pushViewController(vc, animated: true) + // 5. ViewModel에 선택된 빈티지 저장 + viewModel.save(vintage: selectedYear) + // 6. 외부에서 주입받은 onComplete 클로저 실행 + onComplete?(selectedYear) } + + } -extension SelectVintageViewController: UIAdaptivePresentationControllerDelegate { +extension ReusableVintageSelectionViewController: UIAdaptivePresentationControllerDelegate { func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { vintageView.yearPicker.updatePickerView(isModalOpen: false) } diff --git a/DE/DE/Sources/Features/Setting/Views/MyWine/MyWineVintageView.swift b/DE/DE/Sources/Features/Vintage/VintageSelectionView.swift similarity index 93% rename from DE/DE/Sources/Features/Setting/Views/MyWine/MyWineVintageView.swift rename to DE/DE/Sources/Features/Vintage/VintageSelectionView.swift index 7243679d..5a3e3f41 100644 --- a/DE/DE/Sources/Features/Setting/Views/MyWine/MyWineVintageView.swift +++ b/DE/DE/Sources/Features/Vintage/VintageSelectionView.swift @@ -3,8 +3,8 @@ import UIKit import CoreModule import DesignSystem +import SnapKit import Then -import Network class MyWineVintageView: UIView { let despText = "빈티지를 선택해 주세요" @@ -25,11 +25,11 @@ class MyWineVintageView: UIView { fatalError("init(coder:) has not been implemented") } - func setWineName(_ name: String) { + func setTopSection(name: String, descText: String) { topView.setTitleLabel(title: name, titleStyle: AppTextStyle.KR.subtitle1, titleColor: AppColor.purple100, - description: despText, + description: descText, descriptionStyle: AppTextStyle.KR.head, descriptionColor: AppColor.black) } diff --git a/DE/DE/Sources/Features/Setting/Views/MyWine/YearPickerView.swift b/DE/DE/Sources/Features/Vintage/YearPickerView.swift similarity index 100% rename from DE/DE/Sources/Features/Setting/Views/MyWine/YearPickerView.swift rename to DE/DE/Sources/Features/Vintage/YearPickerView.swift