diff --git a/Tving-Clone/Tving-Clone/Application/AppDIContainer.swift b/Tving-Clone/Tving-Clone/Application/AppDIContainer.swift new file mode 100644 index 0000000..91a340e --- /dev/null +++ b/Tving-Clone/Tving-Clone/Application/AppDIContainer.swift @@ -0,0 +1,16 @@ +// +// AppDIContainer.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +final class AppDIContainer { + + func makeContentSceneDIContainer() -> ContentDIContainer { + let dependencies = ContentDIContainer.Dependencies(contentDataSource: ContentDataSource()) + return ContentDIContainer(dependencies: dependencies) + } +} diff --git a/Tving-Clone/Tving-Clone/Application/ContentDIContainer.swift b/Tving-Clone/Tving-Clone/Application/ContentDIContainer.swift new file mode 100644 index 0000000..201828e --- /dev/null +++ b/Tving-Clone/Tving-Clone/Application/ContentDIContainer.swift @@ -0,0 +1,41 @@ +// +// DIConteainer.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +final class ContentDIContainer { + + struct Dependencies { + let contentDataSource: ContentDataSource + } + + private let dependencies: Dependencies + + init(dependencies: Dependencies) { + self.dependencies = dependencies + } + + func makeContentRepository() -> ContentRepository { + return DefaultContentRepository(contentDataSource: dependencies.contentDataSource) + } + + func makeContentUseCase() -> ContentUseCase { + return DefaultContentUseCase(repository: makeContentRepository()) + } + + func makeMainContentViewModel() -> MainContentViewModel { + return MainContentViewModel(contentUseCase: makeContentUseCase()) + } + + func makeMainContentViewController() -> MainContentViewController { + return MainContentViewController(viewModel: makeMainContentViewModel()) + } + + func makeTabBarController() -> TabBarController { + return TabBarController(mainContentViewModel: makeMainContentViewModel()) + } +} diff --git a/Tving-Clone/Tving-Clone/Application/SceneDelegate.swift b/Tving-Clone/Tving-Clone/Application/SceneDelegate.swift index dfe68bd..f847ee4 100644 --- a/Tving-Clone/Tving-Clone/Application/SceneDelegate.swift +++ b/Tving-Clone/Tving-Clone/Application/SceneDelegate.swift @@ -10,16 +10,19 @@ import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - + let appDIContainer = AppDIContainer() func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } - self.window = UIWindow(windowScene: windowScene) - let navigationController = UINavigationController(rootViewController: TabBarController()) - self.window?.rootViewController = navigationController - self.window?.makeKeyAndVisible() - } + let contentSceneDIContainer = appDIContainer.makeContentSceneDIContainer() + let tabBarController = contentSceneDIContainer.makeTabBarController() + + window = UIWindow(windowScene: windowScene) + window?.rootViewController = UINavigationController(rootViewController: tabBarController) + window?.makeKeyAndVisible() + } + func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. diff --git a/Tving-Clone/Tving-Clone/Data/DataSources/ContentDataSource.swift b/Tving-Clone/Tving-Clone/Data/DataSources/ContentDataSource.swift new file mode 100644 index 0000000..5937341 --- /dev/null +++ b/Tving-Clone/Tving-Clone/Data/DataSources/ContentDataSource.swift @@ -0,0 +1,81 @@ +// +// ContentDataSource.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +import Moya + +class ContentDataSource { + private var movieProvider = MoyaProvider(plugins: [MoyaLoggingPlugin()]) +} + +extension ContentDataSource { + func getMovieInfo(completion: @escaping (Result<[Content], Error>) -> Void) { + movieProvider.request(.getMovieData) { result in + switch result { + case .success(let response): + let statusCode = response.statusCode + let data = response.data + do { + let networkResult = try self.judgeStatus(by: statusCode, data, MovieResponseDTO.self).toDomain() + completion(.success(networkResult)) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + + func getDetailInfo(code: String, completion: @escaping (Result) -> Void) { + movieProvider.request(.getDetailData(code: code)) { result in + switch result { + case .success(let response): + let statusCode = response.statusCode + let data = response.data + do { + let networkResult = try self.judgeStatus(by: statusCode, data, DetailResponseDTO.self).toDomain() + completion(.success(networkResult)) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + + private func judgeStatus(by statusCode: Int, _ data: Data, _ object: T.Type) throws -> T { + switch statusCode { + case 200..<205: + return try isValidData(data: data, T.self) + case 400..<500: + throw NetworkError.requestError + case 500: + throw NetworkError.serverError + default: + throw NetworkError.networkFailure + } + } + + private func isValidData(data: Data, _ object: T.Type) throws -> T { + let decoder = JSONDecoder() + guard let decodedData = try? decoder.decode(T.self, from: data) else { + print("⛔️ 디코딩 오류가 발생했습니다 ⛔️") + throw NetworkError.decodingError + } + return decodedData + } +} + +enum NetworkError: Error { + case requestError + case serverError + case networkFailure + case decodingError +} diff --git a/Tving-Clone/Tving-Clone/Data/Repositories/DefaultContentRepository.swift b/Tving-Clone/Tving-Clone/Data/Repositories/DefaultContentRepository.swift new file mode 100644 index 0000000..97f1cd9 --- /dev/null +++ b/Tving-Clone/Tving-Clone/Data/Repositories/DefaultContentRepository.swift @@ -0,0 +1,29 @@ +// +// DefaultContentRepository.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +import Moya + +final class DefaultContentRepository { + + private let contentDataSource: ContentDataSource + + init(contentDataSource: ContentDataSource) { + self.contentDataSource = contentDataSource + } +} + +extension DefaultContentRepository: ContentRepository { + func getMovieInfo(completion: @escaping (Result<[Content], any Error>) -> Void) { + contentDataSource.getMovieInfo(completion: completion) + } + + func getDetailInfo(code: String, completion: @escaping (Result) -> Void) { + contentDataSource.getDetailInfo(code: code, completion: completion) + } +} diff --git a/Tving-Clone/Tving-Clone/Domain/Entities/Content.swift b/Tving-Clone/Tving-Clone/Domain/Entities/Content.swift new file mode 100644 index 0000000..115bdc3 --- /dev/null +++ b/Tving-Clone/Tving-Clone/Domain/Entities/Content.swift @@ -0,0 +1,20 @@ +// +// Movie.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +struct Content { + let data: [ContentData] +} + +struct ContentData { + let image: String + var title: String + var maker: String + var subTitle: String + var ratio: String +} diff --git a/Tving-Clone/Tving-Clone/Models/DetailDataModel.swift b/Tving-Clone/Tving-Clone/Domain/Entities/ContentDetail.swift similarity index 62% rename from Tving-Clone/Tving-Clone/Models/DetailDataModel.swift rename to Tving-Clone/Tving-Clone/Domain/Entities/ContentDetail.swift index d9988f8..d99c999 100644 --- a/Tving-Clone/Tving-Clone/Models/DetailDataModel.swift +++ b/Tving-Clone/Tving-Clone/Domain/Entities/ContentDetail.swift @@ -1,14 +1,13 @@ // -// DetailDataModel.swift +// MovieDetail.swift // Tving-Clone // -// Created by Seonwoo Kim on 5/10/24. +// Created by Seonwoo Kim on 6/7/24. // -import UIKit +import Foundation - -struct DetailDataModel { +struct ContentDetail { var title: String var openDt: String var directors: String diff --git a/Tving-Clone/Tving-Clone/Domain/Repositories/ContentRepository.swift b/Tving-Clone/Tving-Clone/Domain/Repositories/ContentRepository.swift new file mode 100644 index 0000000..98d82c3 --- /dev/null +++ b/Tving-Clone/Tving-Clone/Domain/Repositories/ContentRepository.swift @@ -0,0 +1,13 @@ +// +// ContentRepository.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +protocol ContentRepository { + func getMovieInfo(completion: @escaping (Result<[Content], Error>) -> Void) + func getDetailInfo(code: String, completion: @escaping (Result) -> Void) +} diff --git a/Tving-Clone/Tving-Clone/Domain/UseCases/ContentUseCase.swift b/Tving-Clone/Tving-Clone/Domain/UseCases/ContentUseCase.swift new file mode 100644 index 0000000..19535da --- /dev/null +++ b/Tving-Clone/Tving-Clone/Domain/UseCases/ContentUseCase.swift @@ -0,0 +1,32 @@ +// +// FetchContentUseCase.swift +// Tving-Clone +// +// Created by Seonwoo Kim on 6/7/24. +// + +import Foundation + +protocol ContentUseCase { + func fetchContent(completion: @escaping (Result<[Content], Error>) -> Void) + func fetchContentDetail(code: String, completion: @escaping (Result) -> Void) +} + +final class DefaultContentUseCase { + + private let repository: ContentRepository + + init(repository: ContentRepository) { + self.repository = repository + } +} + +extension DefaultContentUseCase: ContentUseCase { + func fetchContent(completion: @escaping (Result<[Content], any Error>) -> Void) { + repository.getMovieInfo(completion: completion) + } + + func fetchContentDetail(code: String, completion: @escaping (Result) -> Void) { + repository.getDetailInfo(code: code, completion: completion) + } +} diff --git a/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginCompleteViewController.swift b/Tving-Clone/Tving-Clone/Login/ViewControllers/LoginCompleteViewController.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginCompleteViewController.swift rename to Tving-Clone/Tving-Clone/Login/ViewControllers/LoginCompleteViewController.swift diff --git a/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift b/Tving-Clone/Tving-Clone/Login/ViewControllers/LoginViewController.swift similarity index 99% rename from Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift rename to Tving-Clone/Tving-Clone/Login/ViewControllers/LoginViewController.swift index 505f0f4..87a85d9 100644 --- a/Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/LoginViewController.swift +++ b/Tving-Clone/Tving-Clone/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/Login/ViewControllers/NickNameViewController.swift b/Tving-Clone/Tving-Clone/Login/ViewControllers/NickNameViewController.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Presentation/Login/ViewControllers/NickNameViewController.swift rename to Tving-Clone/Tving-Clone/Login/ViewControllers/NickNameViewController.swift diff --git a/Tving-Clone/Tving-Clone/Presentation/Login/Views/LoginCompleteView.swift b/Tving-Clone/Tving-Clone/Login/Views/LoginCompleteView.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Presentation/Login/Views/LoginCompleteView.swift rename to Tving-Clone/Tving-Clone/Login/Views/LoginCompleteView.swift diff --git a/Tving-Clone/Tving-Clone/Presentation/Login/Views/LoginView.swift b/Tving-Clone/Tving-Clone/Login/Views/LoginView.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Presentation/Login/Views/LoginView.swift rename to Tving-Clone/Tving-Clone/Login/Views/LoginView.swift diff --git a/Tving-Clone/Tving-Clone/Presentation/Login/Views/NickNameView.swift b/Tving-Clone/Tving-Clone/Login/Views/NickNameView.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Presentation/Login/Views/NickNameView.swift rename to Tving-Clone/Tving-Clone/Login/Views/NickNameView.swift diff --git a/Tving-Clone/Tving-Clone/Models/MainDataModel.swift b/Tving-Clone/Tving-Clone/Models/MainDataModel.swift deleted file mode 100644 index d7dd8e9..0000000 --- a/Tving-Clone/Tving-Clone/Models/MainDataModel.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// MainDataModel.swift -// Tving-Clone -// -// Created by Seonwoo Kim on 4/28/24. -// - -import UIKit - -struct MainDataModel { - let data: [MainData] -} - -struct MainData { - let image: UIImage - var title: String - var maker: String - var subTitle: String - var ratio: String -} - diff --git a/Tving-Clone/Tving-Clone/Network/MovieTargetType.swift b/Tving-Clone/Tving-Clone/Network/Base/MovieTargetType.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Network/MovieTargetType.swift rename to Tving-Clone/Tving-Clone/Network/Base/MovieTargetType.swift diff --git a/Tving-Clone/Tving-Clone/Network/MoyaLoggingPlugin.swift b/Tving-Clone/Tving-Clone/Network/Base/MoyaLoggingPlugin.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Network/MoyaLoggingPlugin.swift rename to Tving-Clone/Tving-Clone/Network/Base/MoyaLoggingPlugin.swift diff --git a/Tving-Clone/Tving-Clone/Network/NetworkResult.swift b/Tving-Clone/Tving-Clone/Network/Base/NetworkResult.swift similarity index 100% rename from Tving-Clone/Tving-Clone/Network/NetworkResult.swift rename to Tving-Clone/Tving-Clone/Network/Base/NetworkResult.swift diff --git a/Tving-Clone/Tving-Clone/Network/DTO/DetailResponseDTO.swift b/Tving-Clone/Tving-Clone/Network/DTO/DetailResponseDTO.swift index 302d499..66f0c8a 100644 --- a/Tving-Clone/Tving-Clone/Network/DTO/DetailResponseDTO.swift +++ b/Tving-Clone/Tving-Clone/Network/DTO/DetailResponseDTO.swift @@ -60,7 +60,7 @@ struct ShowType: Codable { } extension DetailResponseDTO { - func toAppData() -> DetailDataModel { + func toDomain() -> ContentDetail { let movieInfo = self.movieInfoResult.movieInfo let title = movieInfo.movieNm @@ -70,7 +70,7 @@ extension DetailResponseDTO { let audits = movieInfo.audits.first?.auditNo ?? "" let companys = movieInfo.companys.first?.companyNm ?? "" - return DetailDataModel( + return ContentDetail( title: title, openDt: openDt, directors: directors, diff --git a/Tving-Clone/Tving-Clone/Network/DTO/MovieResponseDTO.swift b/Tving-Clone/Tving-Clone/Network/DTO/MovieResponseDTO.swift index 5b301bd..89df95e 100644 --- a/Tving-Clone/Tving-Clone/Network/DTO/MovieResponseDTO.swift +++ b/Tving-Clone/Tving-Clone/Network/DTO/MovieResponseDTO.swift @@ -37,13 +37,12 @@ enum RankOldAndNew: String, Codable { } extension MovieResponseDTO { - func toAppData() -> [MainDataModel] { - var mainDataModels: [MainDataModel] = [] + func toDomain() -> [Content] { + var mainDataModels: [Content] = [] - var tempData: [MainData] = [] + var tempData: [ContentData] = [] for (index, boxOfficeData) in boxOfficeResult.dailyBoxOfficeList.enumerated() { - let mainData = MainData( - image: .poster4, + let mainData = ContentData(image: "poster4", title: boxOfficeData.movieNm, maker: boxOfficeData.movieCd, subTitle: boxOfficeData.movieCd, @@ -52,7 +51,7 @@ extension MovieResponseDTO { tempData.append(mainData) if (index + 1) % 8 == 0 || index == boxOfficeResult.dailyBoxOfficeList.count - 1 { - let mainDataModel = MainDataModel(data: tempData) + let mainDataModel = Content(data: tempData) mainDataModels.append(mainDataModel) tempData.removeAll() } 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/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,12 @@ 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("네트워크 오류입니다") - } - } - } } 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..f03fe62 100644 --- a/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarController.swift +++ b/Tving-Clone/Tving-Clone/Presentation/TabBar/TabBarController.swift @@ -10,9 +10,19 @@ import SnapKit final class TabBarController: UITabBarController { + private var mainContentViewModel: MainContentViewModel + + 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 viewDidLoad() { super.viewDidLoad() - setTabBarItem() setStyle() } @@ -27,14 +37,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() } } }