From 36e97619db59e8ebd814a41d5367adc2a8cd410d Mon Sep 17 00:00:00 2001 From: kim-seonwoo Date: Fri, 7 Jun 2024 21:38:13 +0900 Subject: [PATCH] =?UTF-8?q?[Fix/#7]=20Presentation=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=EC=97=90=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 --- .../Tving-Clone/Network/MovieService.swift | 87 ------------ .../ViewControllers/LoginViewController.swift | 2 +- .../Presentation/Main/Cells/LiveCell.swift | 4 +- .../Main/Cells/MainCarouselCell.swift | 4 +- .../Main/Cells/MainHeaderView.swift | 2 +- .../Main/Cells/MoviePosterCell.swift | 4 +- .../DetailViewController.swift | 11 +- .../MainContentViewController.swift | 133 ++++++++++-------- .../ViewControllers/MainViewController.swift | 16 ++- .../Presentation/Main/Views/DetailView.swift | 2 +- .../Tving-Clone/Presentation/Observable.swift | 25 ++++ .../TabBar/TabBarController.swift | 28 +++- .../Presentation/TabBar/TabBarItem.swift | 12 +- 13 files changed, 157 insertions(+), 173 deletions(-) delete mode 100644 Tving-Clone/Tving-Clone/Network/MovieService.swift create mode 100644 Tving-Clone/Tving-Clone/Presentation/Observable.swift diff --git a/Tving-Clone/Tving-Clone/Network/MovieService.swift b/Tving-Clone/Tving-Clone/Network/MovieService.swift deleted file mode 100644 index c71087f..0000000 --- a/Tving-Clone/Tving-Clone/Network/MovieService.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// MovieService.swift -// Tving-Clone -// -// Created by Seonwoo Kim on 5/8/24. -// - -import Foundation - -import Moya - -final class MovieService { - static let shared = MovieService() - private var movieProvider = MoyaProvider(plugins: [MoyaLoggingPlugin()]) - - private init() {} -} - -extension MovieService { - func getMovieInfo(completion: @escaping (NetworkResult) -> Void) { - movieProvider.request(.getMovieData) { result in - switch result { - case .success(let response): - let statusCode = response.statusCode - let data = response.data - - let networkResult = self.judgeStatus(by: statusCode, data, MovieResponseDTO.self) - completion(networkResult) - - case .failure: - completion(.networkFail) - } - } - } - - func getDetailInfo(code: String, completion: @escaping (NetworkResult) -> Void) { - movieProvider.request(.getDetailData(code: code)) { result in - switch result { - case .success(let response): - let statusCode = response.statusCode - let data = response.data - - let networkResult = self.judgeStatus(by: statusCode, data, DetailResponseDTO.self) - completion(networkResult) - - case .failure: - completion(.networkFail) - } - } - } - - - public func judgeStatus(by statusCode: Int, _ data: Data, _ object: T.Type) -> NetworkResult { - - switch statusCode { - case 200..<205: - return isValidData(data: data, T.self) - case 400..<500: - return .requestErr - case 500: - return .serverErr - default: - return .networkFail - } - } - - - private func isValidData(data: Data, _ object: T.Type) -> NetworkResult { - let decoder = JSONDecoder() - guard let decodedData = try? decoder.decode(T.self, from: data) else { - print("⛔️ \(self)에서 디코딩 오류가 발생했습니다 ⛔️") - return .pathErr - } - - if let movieResponseDTO = decodedData as? MovieResponseDTO { - let appData = movieResponseDTO.toAppData() - return .success(appData as Any) - } else if let detailResponseDTO = decodedData as? DetailResponseDTO { - let appData = detailResponseDTO.toAppData() - return .success(appData as Any) - } else { - return .pathErr - } - } -} - - diff --git a/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift b/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift index 505f0f4..87a85d9 100644 --- a/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift +++ b/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift @@ -95,7 +95,7 @@ extension LoginViewController { nickNameViewController.modalPresentationStyle = .formSheet self.present(nickNameViewController, animated: true) } - + @objc private func textFieldChanged() { if let idText = loginView.idTextField.text, let passwordText = loginView.passwordTextField.text { diff --git a/Tving-Clone/Tving-Clone/Presentation/Main/Cells/LiveCell.swift b/Tving-Clone/Tving-Clone/Presentation/Main/Cells/LiveCell.swift index f584ad1..0960baa 100644 --- a/Tving-Clone/Tving-Clone/Presentation/Main/Cells/LiveCell.swift +++ b/Tving-Clone/Tving-Clone/Presentation/Main/Cells/LiveCell.swift @@ -82,8 +82,8 @@ final class LiveCell: UICollectionViewCell { } } - func bindData(data: MainData, rank: Int) { - liveImageView.image = data.image + func bindData(data: ContentData, rank: Int) { + liveImageView.image = UIImage(named: data.image) rankLabel.text = "\(rank)" makerLabel.text = data.maker subTitleLabel.text = data.subTitle diff --git a/Tving-Clone/Tving-Clone/Presentation/Main/Cells/MainCarouselCell.swift b/Tving-Clone/Tving-Clone/Presentation/Main/Cells/MainCarouselCell.swift index bf1616f..a59ae4b 100644 --- a/Tving-Clone/Tving-Clone/Presentation/Main/Cells/MainCarouselCell.swift +++ b/Tving-Clone/Tving-Clone/Presentation/Main/Cells/MainCarouselCell.swift @@ -81,14 +81,14 @@ final class MainCarouselCell: UICollectionViewCell { } } - func bindData(data: MainDataModel) { + func bindData(data: Content) { pageViews.removeAll() totalPage = data.data.count pageControl.numberOfPages = totalPage scrollView.contentSize = CGSize(width: (375 * totalPage), height: 498) for i in 0.. Int { - return mainData.count + return viewModel.content.value.count } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { @@ -81,7 +94,7 @@ extension MainContentViewController: UICollectionViewDataSource { case .MainCarousel: return 1 default: - return mainData[section].data.count + return viewModel.content.value[section].data.count } } @@ -114,13 +127,13 @@ extension MainContentViewController: UICollectionViewDataSource { case .MainCarousel: guard let cell = rootView.mainCollectionView.dequeueReusableCell(withReuseIdentifier: MainCarouselCell.identifier, for: indexPath) as? MainCarouselCell else { return UICollectionViewCell()} - let cellData = mainData[indexPath.section] + let cellData = viewModel.content.value[indexPath.section] cell.bindData(data: cellData) return cell case .Live: guard let cell = rootView.mainCollectionView.dequeueReusableCell(withReuseIdentifier: LiveCell.identifier, for: indexPath) as? LiveCell else { return UICollectionViewCell()} - let cellData = (mainData[indexPath.section].data[indexPath.row]) + let cellData = (viewModel.content.value[indexPath.section].data[indexPath.row]) cell.bindData(data: cellData, rank: indexPath.row + 1) return cell @@ -132,55 +145,55 @@ extension MainContentViewController: UICollectionViewDataSource { case .RecommendedContent, .Paramount, .MovieDictionary: guard let cell = rootView.mainCollectionView.dequeueReusableCell(withReuseIdentifier: MoviePosterCell.identifier, for: indexPath) as? MoviePosterCell else { return UICollectionViewCell()} - let cellData = mainData[indexPath.section].data[indexPath.row] + let cellData = viewModel.content.value[indexPath.section].data[indexPath.row] cell.bindData(data: cellData) cell.delegate = self return cell } } - - private func requestMovieInfo() { - MovieService.shared.getMovieInfo { [weak self] response in - switch response { - case .success(let data): - if let data = data as? [MainDataModel] { - self?.mainData = data - } - case .requestErr: - print("요청 오류 입니다") - case .decodedErr: - print("디코딩 오류 입니다") - case .pathErr: - print("경로 오류 입니다") - case .serverErr: - print("서버 오류입니다") - case .networkFail: - print("네트워크 오류입니다") - } - } - } - - private func requestDetailInfo(code: String, completion: @escaping (DetailDataModel) -> Void) { - MovieService.shared.getDetailInfo(code: code) { [weak self] response in - switch response { - case .success(let data): - if let detailData = data as? DetailDataModel { - // 비동기 작업이 완료된 후에 클로저 내부에서 completion 블록을 호출하여 다음 작업을 실행합니다. - completion(detailData) - } - case .requestErr: - print("요청 오류 입니다") - case .decodedErr: - print("디코딩 오류 입니다") - case .pathErr: - print("경로 오류 입니다") - case .serverErr: - print("서버 오류입니다") - case .networkFail: - print("네트워크 오류입니다") - } - } - } +// +// private func requestMovieInfo() { +// MovieService.shared.getMovieInfo { [weak self] response in +// switch response { +// case .success(let data): +// if let data = data as? [MainDataModel] { +// self?.mainData = data +// } +// case .requestErr: +// print("요청 오류 입니다") +// case .decodedErr: +// print("디코딩 오류 입니다") +// case .pathErr: +// print("경로 오류 입니다") +// case .serverErr: +// print("서버 오류입니다") +// case .networkFail: +// print("네트워크 오류입니다") +// } +// } +// } + +// private func requestDetailInfo(code: String, completion: @escaping (DetailDataModel) -> Void) { +// MovieService.shared.getDetailInfo(code: code) { [weak self] response in +// switch response { +// case .success(let data): +// if let detailData = data as? DetailDataModel { +// // 비동기 작업이 완료된 후에 클로저 내부에서 completion 블록을 호출하여 다음 작업을 실행합니다. +// completion(detailData) +// } +// case .requestErr: +// print("요청 오류 입니다") +// case .decodedErr: +// print("디코딩 오류 입니다") +// case .pathErr: +// print("경로 오류 입니다") +// case .serverErr: +// print("서버 오류입니다") +// case .networkFail: +// print("네트워크 오류입니다") +// } +// } +// } } extension MainContentViewController: UIScrollViewDelegate { diff --git a/Tving-Clone/Tving-Clone/Presentation/Main/ViewControllers/MainViewController.swift b/Tving-Clone/Tving-Clone/Presentation/Main/ViewControllers/MainViewController.swift index 11e4611..24b6bee 100644 --- a/Tving-Clone/Tving-Clone/Presentation/Main/ViewControllers/MainViewController.swift +++ b/Tving-Clone/Tving-Clone/Presentation/Main/ViewControllers/MainViewController.swift @@ -9,7 +9,11 @@ import UIKit import SnapKit final class MainViewController: UIViewController { - private let mainvc = MainContentViewController() + private let mainContentViewModel: MainContentViewModel + + private lazy var mainvc: MainContentViewController = { + return MainContentViewController(viewModel: mainContentViewModel) + }() private let onAirVC = OnAirViewController() private let tvProgramVC = TVProgramViewController() private let movieVC = MovieViewController() @@ -47,6 +51,16 @@ final class MainViewController: UIViewController { } } + init(mainContentViewModel: MainContentViewModel) { + self.mainContentViewModel = mainContentViewModel + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { self.navigationController?.navigationBar.isHidden = true } diff --git a/Tving-Clone/Tving-Clone/Presentation/Main/Views/DetailView.swift b/Tving-Clone/Tving-Clone/Presentation/Main/Views/DetailView.swift index 87073d2..32d05db 100644 --- a/Tving-Clone/Tving-Clone/Presentation/Main/Views/DetailView.swift +++ b/Tving-Clone/Tving-Clone/Presentation/Main/Views/DetailView.swift @@ -58,7 +58,7 @@ final class DetailView: UIView { } } - func configure(with detailData: DetailDataModel) { + func configure(with detailData: ContentDetail) { let detailDataList = [ detailData.title, detailData.openDt, diff --git a/Tving-Clone/Tving-Clone/Presentation/Observable.swift b/Tving-Clone/Tving-Clone/Presentation/Observable.swift new file mode 100644 index 0000000..478bcf2 --- /dev/null +++ b/Tving-Clone/Tving-Clone/Presentation/Observable.swift @@ -0,0 +1,25 @@ +// +// Observable.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +class Observable { + var value: T { + didSet { + listener?(value) + } + } + + private var listener: ((T) -> Void)? + + init(_ value: T) { + self.value = value + } + + func bind(_ listener: @escaping (T) -> Void) { + self.listener = listener + listener(value) + } +} diff --git a/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarController.swift b/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarController.swift index e44c1ef..d0b9d74 100644 --- a/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarController.swift +++ b/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarController.swift @@ -5,17 +5,34 @@ // Created by Seonwoo Kim on 4/29/24. // +// +// TabBarController.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 4/29/24. +// + import UIKit import SnapKit final class TabBarController: UITabBarController { - override func viewDidLoad() { - super.viewDidLoad() - + private let mainContentViewModel: MainContentViewModel + + init(mainContentViewModel: MainContentViewModel) { + self.mainContentViewModel = mainContentViewModel + super.init(nibName: nil, bundle: nil) setTabBarItem() setStyle() } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + } private func setStyle() { tabBar.backgroundColor = .gray5 @@ -27,14 +44,11 @@ final class TabBarController: UITabBarController { var tabBarViewControllers: [UIViewController] = [] for item in TabBarItem.allCases { - guard let viewController = item.changedViewController else { - continue - } + let viewController = item.changedViewController(mainContentViewModel: mainContentViewModel) viewController.tabBarItem = UITabBarItem(title: item.title, image: item.image, selectedImage: item.selectedImage) tabBarViewControllers.append(viewController) } self.viewControllers = tabBarViewControllers } - } diff --git a/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarItem.swift b/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarItem.swift index ee619af..8fa7e3a 100644 --- a/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarItem.swift +++ b/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarItem.swift @@ -51,16 +51,12 @@ extension TabBarItem { } } - var changedViewController: UIViewController? { + func changedViewController(mainContentViewModel: MainContentViewModel) -> UIViewController { switch self { case .home: - MainViewController() - case .soon: - LoginViewController() - case .search: - LoginViewController() - case .timeline: - LoginViewController() + return MainViewController(mainContentViewModel: mainContentViewModel) + case .soon, .search, .timeline: + return LoginViewController() } } }