From ab75a351ca20535eb78829a890adac3f3f390020 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 8 Dec 2023 02:19:30 +0900 Subject: [PATCH 1/4] Refactor/#5 Observable --- .../SOPTWeather.xcodeproj/project.pbxproj | 16 +++++ .../Global/Protocols/Observable.swift | 27 +++++++++ .../ViewModel/LocationListViewModel.swift | 58 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 SOPTWeather/SOPTWeather/Global/Protocols/Observable.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/LocationList/ViewModel/LocationListViewModel.swift diff --git a/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj b/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj index a6d83c2..f8bac65 100644 --- a/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj +++ b/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 3651D8BD2B20639600BE0699 /* LocationListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */; }; + 3651D8BF2B21074F00BE0699 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3651D8BE2B21074F00BE0699 /* Observable.swift */; }; 366014902AFB70B200D3D4F7 /* CityWeatherDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3660148F2AFB70B200D3D4F7 /* CityWeatherDetailView.swift */; }; 366014932AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */; }; 366014952AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */; }; @@ -48,6 +50,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationListViewModel.swift; sourceTree = ""; }; + 3651D8BE2B21074F00BE0699 /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; 3660148F2AFB70B200D3D4F7 /* CityWeatherDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityWeatherDetailView.swift; sourceTree = ""; }; 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeWeatherCollectionViewCell.swift; sourceTree = ""; }; 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeeklyWeatherCollectionViewCell.swift; sourceTree = ""; }; @@ -102,6 +106,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3651D8BB2B20638800BE0699 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 366014912AFB739B00D3D4F7 /* Cells */ = { isa = PBXGroup; children = ( @@ -253,6 +265,7 @@ isa = PBXGroup; children = ( 366014962AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift */, + 3651D8BE2B21074F00BE0699 /* Observable.swift */, ); path = Protocols; sourceTree = ""; @@ -260,6 +273,7 @@ 36E60E862AE2EC6B005035D3 /* LocationList */ = { isa = PBXGroup; children = ( + 3651D8BB2B20638800BE0699 /* ViewModel */, 36E994BD2AFAAE4100F1B2C9 /* Cell */, 36E60E882AE2ED11005035D3 /* ViewController */, 36E60E892AE2ED1C005035D3 /* View */, @@ -414,12 +428,14 @@ 36E60E732AE2595D005035D3 /* Font.swift in Sources */, 36E60E8B2AE2F0AC005035D3 /* WeatherDetailView.swift in Sources */, 3660149F2AFE21A300D3D4F7 /* SectionBackgroundView.swift in Sources */, + 3651D8BD2B20639600BE0699 /* LocationListViewModel.swift in Sources */, 366014952AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift in Sources */, 366646612B03715B006C8B5E /* WeatherModel.swift in Sources */, 36E60E772AE25975005035D3 /* ImageLiterals.swift in Sources */, 36E60E8D2AE2F0C6005035D3 /* WeatherDetailViewController.swift in Sources */, 36EC08622B023348008A820D /* GetService.swift in Sources */, 366014932AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift in Sources */, + 3651D8BF2B21074F00BE0699 /* Observable.swift in Sources */, 366014992AFE0E0500D3D4F7 /* SummaryCollectionViewCell.swift in Sources */, 36B2B80F2AEA4E7200755C63 /* TimeWeatherView.swift in Sources */, 36E60E412AE180FA005035D3 /* AppDelegate.swift in Sources */, diff --git a/SOPTWeather/SOPTWeather/Global/Protocols/Observable.swift b/SOPTWeather/SOPTWeather/Global/Protocols/Observable.swift new file mode 100644 index 0000000..4ea8d2a --- /dev/null +++ b/SOPTWeather/SOPTWeather/Global/Protocols/Observable.swift @@ -0,0 +1,27 @@ +// +// Observable.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/7/23. +// + +import Foundation + +class Observable { + private var listener: ((T) -> Void)? + + var value: T { + didSet { + listener?(value) + } + } + + init(_ value: T){ + self.value = value + } + + func bind(_ closure: @escaping (T) -> Void ) { + closure(value) + listener = closure + } +} diff --git a/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewModel/LocationListViewModel.swift b/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewModel/LocationListViewModel.swift new file mode 100644 index 0000000..bb6a2b3 --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewModel/LocationListViewModel.swift @@ -0,0 +1,58 @@ +// +// LocationListViewModel.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/6/23. +// + +import Foundation +import UIKit + +protocol ObservableViewModelProtocol { + func fetchWeatherData() + func setError(_ message: String) + var weather: Observable<[WeatherDTO]> { get set } + var errorMessage: Observable { get set } + var error: Observable { get set } + } + +class LocationListViewModel: NSObject, ObservableViewModelProtocol { + + let locationList = ["iksan", "jeonju", "jeju", "cheonan", "cheongju", "chuncheon"] + + var weather: Observable<[WeatherDTO]> = Observable([]) + var errorMessage: Observable = Observable(nil) + var error: Observable = Observable(false) + + func fetchWeatherData() { + locationList.forEach { city in + Task { + if let result = try await GetWeatherService.shared.GetWeatherInfo(location: city) { + print(result) + weather.value.append(result) + } + } + } + + } + + func setError(_ message: String) { + self.errorMessage = Observable(message) + self.error = Observable(true) + } +} + + +// 근데 여기서 만약 아직 네트워크가 실행되지 않았다면 ? 테이블 뷰가 나타나지 않을거임.. 고민해보자 +extension LocationListViewModel: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return weather.value.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: WeatherListTableViewCell.cellReuseIdentifier, for: indexPath) as! WeatherListTableViewCell + // cell.weatherData = infoList[indexPath.row] + cell.selectionStyle = .none + return cell + } +} From 1d2239828860929cecc1c48fb8ae471fe34e5c0e Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 15 Dec 2023 23:15:20 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Feat/#5=20WeatherDetailView=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SOPTWeather.xcodeproj/project.pbxproj | 64 +++-- .../Application/SceneDelegate.swift | 2 +- .../Cell/WeatherListTableViewCell.swift | 21 +- .../View/LocationListElementView.swift | 4 +- .../LocationListViewController.swift | 57 +--- .../WeatherDetail/Cells/HeaderView.swift | 20 -- .../WeatherTimeHeaderView.swift} | 44 +-- .../Cells/Helper/WeekHeaderView.swift | 68 +++++ .../Cells/SectionBackgroundView.swift | 34 --- .../Cells/TimeWeatherTableViewCell.swift | 95 +++++++ .../Cells/WeekWeatherTableViewCell.swift | 106 +++++++ .../CityWeatherDetailViewController.swift | 46 +++ .../WeatherDetailViewController.swift | 69 ----- .../Views/CityWeatherDetailView.swift | 262 ------------------ .../WeatherDetail/Views/CityWeatherView.swift | 147 ++++++++++ .../WeatherDetail/Views/TimeWeatherView.swift | 88 ------ .../Views/WeatherDetailView.swift | 226 --------------- .../WeatherDetailViewModel.swift | 152 ++++++++++ 18 files changed, 693 insertions(+), 812 deletions(-) delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/HeaderView.swift rename SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/{SummaryCollectionViewCell.swift => Helper/WeatherTimeHeaderView.swift} (71%) create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SectionBackgroundView.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeekWeatherTableViewCell.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/CityWeatherDetailViewController.swift delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/WeatherDetailViewController.swift delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherDetailView.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/TimeWeatherView.swift delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/WeatherDetailView.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/WeatherDetailViewModel.swift diff --git a/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj b/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj index f8bac65..301626f 100644 --- a/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj +++ b/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj @@ -9,20 +9,21 @@ /* Begin PBXBuildFile section */ 3651D8BD2B20639600BE0699 /* LocationListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */; }; 3651D8BF2B21074F00BE0699 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3651D8BE2B21074F00BE0699 /* Observable.swift */; }; - 366014902AFB70B200D3D4F7 /* CityWeatherDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3660148F2AFB70B200D3D4F7 /* CityWeatherDetailView.swift */; }; 366014932AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */; }; 366014952AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */; }; 366014972AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014962AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift */; }; - 366014992AFE0E0500D3D4F7 /* SummaryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014982AFE0E0500D3D4F7 /* SummaryCollectionViewCell.swift */; }; 3660149D2AFE1E9B00D3D4F7 /* UIImage+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3660149C2AFE1E9B00D3D4F7 /* UIImage+.swift */; }; - 3660149F2AFE21A300D3D4F7 /* SectionBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3660149E2AFE21A300D3D4F7 /* SectionBackgroundView.swift */; }; - 366014A12AFE2CA900D3D4F7 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014A02AFE2CA900D3D4F7 /* HeaderView.swift */; }; 366646612B03715B006C8B5E /* WeatherModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366646602B03715B006C8B5E /* WeatherModel.swift */; }; 366646632B03898B006C8B5E /* GetWeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366646622B03898B006C8B5E /* GetWeatherService.swift */; }; 366646652B04A52F006C8B5E /* GetTimeWeatherInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366646642B04A52F006C8B5E /* GetTimeWeatherInfo.swift */; }; 3697EE9E2AEB249200115D49 /* WeatherDetailPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3697EE9D2AEB249200115D49 /* WeatherDetailPageViewController.swift */; }; 36B2B80D2AEA4D7400755C63 /* TimeWeatherModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B2B80C2AEA4D7400755C63 /* TimeWeatherModel.swift */; }; - 36B2B80F2AEA4E7200755C63 /* TimeWeatherView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B2B80E2AEA4E7200755C63 /* TimeWeatherView.swift */; }; + 36CC2C3A2B2742360066B942 /* CityWeatherView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC2C392B2742360066B942 /* CityWeatherView.swift */; }; + 36CC2C3E2B274EA80066B942 /* WeatherTimeHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC2C3D2B274EA80066B942 /* WeatherTimeHeaderView.swift */; }; + 36CC2C412B2761F00066B942 /* TimeWeatherTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC2C402B2761F00066B942 /* TimeWeatherTableViewCell.swift */; }; + 36CC2C432B276E370066B942 /* WeekWeatherTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC2C422B276E370066B942 /* WeekWeatherTableViewCell.swift */; }; + 36CC2C452B2770730066B942 /* WeekHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC2C442B2770730066B942 /* WeekHeaderView.swift */; }; + 36CC2C472B2770BC0066B942 /* WeatherDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC2C462B2770BC0066B942 /* WeatherDetailViewModel.swift */; }; 36E60E412AE180FA005035D3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E402AE180FA005035D3 /* AppDelegate.swift */; }; 36E60E432AE180FA005035D3 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E422AE180FA005035D3 /* SceneDelegate.swift */; }; 36E60E4A2AE180FB005035D3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 36E60E492AE180FB005035D3 /* Assets.xcassets */; }; @@ -40,8 +41,7 @@ 36E60E802AE2DF6A005035D3 /* LocationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E7F2AE2DF6A005035D3 /* LocationListView.swift */; }; 36E60E832AE2E0AB005035D3 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 36E60E822AE2E0AB005035D3 /* SnapKit */; }; 36E60E852AE2E768005035D3 /* LocationListElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E842AE2E768005035D3 /* LocationListElementView.swift */; }; - 36E60E8B2AE2F0AC005035D3 /* WeatherDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E8A2AE2F0AC005035D3 /* WeatherDetailView.swift */; }; - 36E60E8D2AE2F0C6005035D3 /* WeatherDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E8C2AE2F0C6005035D3 /* WeatherDetailViewController.swift */; }; + 36E60E8D2AE2F0C6005035D3 /* CityWeatherDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E60E8C2AE2F0C6005035D3 /* CityWeatherDetailViewController.swift */; }; 36E994BF2AFAAE6C00F1B2C9 /* WeatherListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E994BE2AFAAE6C00F1B2C9 /* WeatherListTableViewCell.swift */; }; 36EC085C2B02243F008A820D /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36EC085B2B02243F008A820D /* Config.swift */; }; 36EC085E2B0228D9008A820D /* NetworkResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36EC085D2B0228D9008A820D /* NetworkResult.swift */; }; @@ -52,20 +52,21 @@ /* Begin PBXFileReference section */ 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationListViewModel.swift; sourceTree = ""; }; 3651D8BE2B21074F00BE0699 /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; - 3660148F2AFB70B200D3D4F7 /* CityWeatherDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityWeatherDetailView.swift; sourceTree = ""; }; 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeWeatherCollectionViewCell.swift; sourceTree = ""; }; 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeeklyWeatherCollectionViewCell.swift; sourceTree = ""; }; 366014962AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewCellReuseProtocol.swift; sourceTree = ""; }; - 366014982AFE0E0500D3D4F7 /* SummaryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SummaryCollectionViewCell.swift; sourceTree = ""; }; 3660149C2AFE1E9B00D3D4F7 /* UIImage+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+.swift"; sourceTree = ""; }; - 3660149E2AFE21A300D3D4F7 /* SectionBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionBackgroundView.swift; sourceTree = ""; }; - 366014A02AFE2CA900D3D4F7 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 366646602B03715B006C8B5E /* WeatherModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherModel.swift; sourceTree = ""; }; 366646622B03898B006C8B5E /* GetWeatherService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetWeatherService.swift; sourceTree = ""; }; 366646642B04A52F006C8B5E /* GetTimeWeatherInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetTimeWeatherInfo.swift; sourceTree = ""; }; 3697EE9D2AEB249200115D49 /* WeatherDetailPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherDetailPageViewController.swift; sourceTree = ""; }; 36B2B80C2AEA4D7400755C63 /* TimeWeatherModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeWeatherModel.swift; sourceTree = ""; }; - 36B2B80E2AEA4E7200755C63 /* TimeWeatherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeWeatherView.swift; sourceTree = ""; }; + 36CC2C392B2742360066B942 /* CityWeatherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityWeatherView.swift; sourceTree = ""; }; + 36CC2C3D2B274EA80066B942 /* WeatherTimeHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherTimeHeaderView.swift; sourceTree = ""; }; + 36CC2C402B2761F00066B942 /* TimeWeatherTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeWeatherTableViewCell.swift; sourceTree = ""; }; + 36CC2C422B276E370066B942 /* WeekWeatherTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekWeatherTableViewCell.swift; sourceTree = ""; }; + 36CC2C442B2770730066B942 /* WeekHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekHeaderView.swift; sourceTree = ""; }; + 36CC2C462B2770BC0066B942 /* WeatherDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherDetailViewModel.swift; sourceTree = ""; }; 36E60E3D2AE180FA005035D3 /* SOPTWeather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SOPTWeather.app; sourceTree = BUILT_PRODUCTS_DIR; }; 36E60E402AE180FA005035D3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 36E60E422AE180FA005035D3 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -84,8 +85,7 @@ 36E60E7D2AE2DF59005035D3 /* LocationListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationListViewController.swift; sourceTree = ""; }; 36E60E7F2AE2DF6A005035D3 /* LocationListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationListView.swift; sourceTree = ""; }; 36E60E842AE2E768005035D3 /* LocationListElementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationListElementView.swift; sourceTree = ""; }; - 36E60E8A2AE2F0AC005035D3 /* WeatherDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherDetailView.swift; sourceTree = ""; }; - 36E60E8C2AE2F0C6005035D3 /* WeatherDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherDetailViewController.swift; sourceTree = ""; }; + 36E60E8C2AE2F0C6005035D3 /* CityWeatherDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityWeatherDetailViewController.swift; sourceTree = ""; }; 36E994BE2AFAAE6C00F1B2C9 /* WeatherListTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherListTableViewCell.swift; sourceTree = ""; }; 36EC085B2B02243F008A820D /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; 36EC085D2B0228D9008A820D /* NetworkResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkResult.swift; sourceTree = ""; }; @@ -117,11 +117,11 @@ 366014912AFB739B00D3D4F7 /* Cells */ = { isa = PBXGroup; children = ( - 366014982AFE0E0500D3D4F7 /* SummaryCollectionViewCell.swift */, + 36CC2C3F2B274EAE0066B942 /* Helper */, 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */, 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */, - 3660149E2AFE21A300D3D4F7 /* SectionBackgroundView.swift */, - 366014A02AFE2CA900D3D4F7 /* HeaderView.swift */, + 36CC2C402B2761F00066B942 /* TimeWeatherTableViewCell.swift */, + 36CC2C422B276E370066B942 /* WeekWeatherTableViewCell.swift */, ); path = Cells; sourceTree = ""; @@ -130,7 +130,7 @@ isa = PBXGroup; children = ( 3697EE9D2AEB249200115D49 /* WeatherDetailPageViewController.swift */, - 36E60E8C2AE2F0C6005035D3 /* WeatherDetailViewController.swift */, + 36E60E8C2AE2F0C6005035D3 /* CityWeatherDetailViewController.swift */, ); path = ViewControllers; sourceTree = ""; @@ -138,13 +138,20 @@ 3660149B2AFE0E1500D3D4F7 /* Views */ = { isa = PBXGroup; children = ( - 3660148F2AFB70B200D3D4F7 /* CityWeatherDetailView.swift */, - 36E60E8A2AE2F0AC005035D3 /* WeatherDetailView.swift */, - 36B2B80E2AEA4E7200755C63 /* TimeWeatherView.swift */, + 36CC2C392B2742360066B942 /* CityWeatherView.swift */, ); path = Views; sourceTree = ""; }; + 36CC2C3F2B274EAE0066B942 /* Helper */ = { + isa = PBXGroup; + children = ( + 36CC2C3D2B274EA80066B942 /* WeatherTimeHeaderView.swift */, + 36CC2C442B2770730066B942 /* WeekHeaderView.swift */, + ); + path = Helper; + sourceTree = ""; + }; 36E60E342AE180F9005035D3 = { isa = PBXGroup; children = ( @@ -287,6 +294,7 @@ 3660149A2AFE0E0D00D3D4F7 /* ViewControllers */, 3660149B2AFE0E1500D3D4F7 /* Views */, 366014912AFB739B00D3D4F7 /* Cells */, + 36CC2C462B2770BC0066B942 /* WeatherDetailViewModel.swift */, ); path = WeatherDetail; sourceTree = ""; @@ -426,29 +434,29 @@ 36E60E7A2AE26566005035D3 /* UIView+.swift in Sources */, 36EC085C2B02243F008A820D /* Config.swift in Sources */, 36E60E732AE2595D005035D3 /* Font.swift in Sources */, - 36E60E8B2AE2F0AC005035D3 /* WeatherDetailView.swift in Sources */, - 3660149F2AFE21A300D3D4F7 /* SectionBackgroundView.swift in Sources */, + 36CC2C3A2B2742360066B942 /* CityWeatherView.swift in Sources */, 3651D8BD2B20639600BE0699 /* LocationListViewModel.swift in Sources */, 366014952AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift in Sources */, 366646612B03715B006C8B5E /* WeatherModel.swift in Sources */, 36E60E772AE25975005035D3 /* ImageLiterals.swift in Sources */, - 36E60E8D2AE2F0C6005035D3 /* WeatherDetailViewController.swift in Sources */, + 36E60E8D2AE2F0C6005035D3 /* CityWeatherDetailViewController.swift in Sources */, 36EC08622B023348008A820D /* GetService.swift in Sources */, 366014932AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift in Sources */, 3651D8BF2B21074F00BE0699 /* Observable.swift in Sources */, - 366014992AFE0E0500D3D4F7 /* SummaryCollectionViewCell.swift in Sources */, - 36B2B80F2AEA4E7200755C63 /* TimeWeatherView.swift in Sources */, 36E60E412AE180FA005035D3 /* AppDelegate.swift in Sources */, 36E60E7E2AE2DF59005035D3 /* LocationListViewController.swift in Sources */, 3660149D2AFE1E9B00D3D4F7 /* UIImage+.swift in Sources */, + 36CC2C3E2B274EA80066B942 /* WeatherTimeHeaderView.swift in Sources */, 3697EE9E2AEB249200115D49 /* WeatherDetailPageViewController.swift in Sources */, 36E60E852AE2E768005035D3 /* LocationListElementView.swift in Sources */, - 366014902AFB70B200D3D4F7 /* CityWeatherDetailView.swift in Sources */, + 36CC2C452B2770730066B942 /* WeekHeaderView.swift in Sources */, + 36CC2C412B2761F00066B942 /* TimeWeatherTableViewCell.swift in Sources */, + 36CC2C432B276E370066B942 /* WeekWeatherTableViewCell.swift in Sources */, + 36CC2C472B2770BC0066B942 /* WeatherDetailViewModel.swift in Sources */, 36EC085E2B0228D9008A820D /* NetworkResult.swift in Sources */, 366646632B03898B006C8B5E /* GetWeatherService.swift in Sources */, 36EC08602B0228F9008A820D /* NetworkError.swift in Sources */, 36E60E432AE180FA005035D3 /* SceneDelegate.swift in Sources */, - 366014A12AFE2CA900D3D4F7 /* HeaderView.swift in Sources */, 366646652B04A52F006C8B5E /* GetTimeWeatherInfo.swift in Sources */, 36E994BF2AFAAE6C00F1B2C9 /* WeatherListTableViewCell.swift in Sources */, ); diff --git a/SOPTWeather/SOPTWeather/Application/SceneDelegate.swift b/SOPTWeather/SOPTWeather/Application/SceneDelegate.swift index c400637..c01bcfe 100644 --- a/SOPTWeather/SOPTWeather/Application/SceneDelegate.swift +++ b/SOPTWeather/SOPTWeather/Application/SceneDelegate.swift @@ -15,7 +15,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { 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: LocationListViewController()) + let navigationController = UINavigationController(rootViewController: CityWeatherDetailViewController()) self.window?.rootViewController = navigationController self.window?.makeKeyAndVisible() diff --git a/SOPTWeather/SOPTWeather/Presentation/LocationList/Cell/WeatherListTableViewCell.swift b/SOPTWeather/SOPTWeather/Presentation/LocationList/Cell/WeatherListTableViewCell.swift index 22970dc..1ef8813 100644 --- a/SOPTWeather/SOPTWeather/Presentation/LocationList/Cell/WeatherListTableViewCell.swift +++ b/SOPTWeather/SOPTWeather/Presentation/LocationList/Cell/WeatherListTableViewCell.swift @@ -11,11 +11,7 @@ class WeatherListTableViewCell: UITableViewCell { static let cellReuseIdentifier = "cellReuseIdentifier" - var weatherData = (cityName: "", weatherText: "", maxminTemp: "", weatherinfomation: []){ - didSet{ - bindData() - } - } + var weatherData = (cityName: "", weatherText: "", maxminTemp: "", weatherinfomation: []) private let backgroundImageView: UIImageView = { let imageView = UIImageView() @@ -75,21 +71,6 @@ class WeatherListTableViewCell: UITableViewCell { contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)) } - func bindData() { - locationTitleLabel.text = weatherData.cityName - locationLabel.text = weatherData.subTitle - weatherLabel.text = weatherData.weatherText - - if weatherData.currentTemp == "" { - tempLabel.text = weatherData.weatherinfomation.first?.tempText - } else { - tempLabel.text = weatherData.currentTemp - } - - maxMinTempLabel.text = weatherData.maxminTemp - setUI() - } - private func setUI(){ setViewHierarchy() setConstraints() diff --git a/SOPTWeather/SOPTWeather/Presentation/LocationList/View/LocationListElementView.swift b/SOPTWeather/SOPTWeather/Presentation/LocationList/View/LocationListElementView.swift index 21e8146..86451b4 100644 --- a/SOPTWeather/SOPTWeather/Presentation/LocationList/View/LocationListElementView.swift +++ b/SOPTWeather/SOPTWeather/Presentation/LocationList/View/LocationListElementView.swift @@ -70,9 +70,9 @@ class LocationListElementView: UIButton { func bindData() { locationTitleLabel.text = weatherData.cityName - locationLabel.text = weatherData.subTitle + // locationLabel.text = weatherData.subTitle weatherLabel.text = weatherData.weatherText - tempLabel.text = weatherData.weatherinfomation.first?.tempText + // tempLabel.text = weatherData.weatherinfomation.first?.tempText maxMinTempLabel.text = weatherData.maxminTemp setUI() } diff --git a/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewController/LocationListViewController.swift b/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewController/LocationListViewController.swift index 8766a22..3072173 100644 --- a/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewController/LocationListViewController.swift +++ b/SOPTWeather/SOPTWeather/Presentation/LocationList/ViewController/LocationListViewController.swift @@ -10,54 +10,23 @@ import UIKit class LocationListViewController: UIViewController { let pageController = WeatherDetailPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal) - let locationView = LocationListView() - let locationList = ["iksan", "jeonju", "jeju", "cheonan", "cheongju", "chuncheon"] - var infoList: [] = [] + let locationListView = LocationListView() - override func viewDidLoad() { - super.viewDidLoad() - navigationController?.isNavigationBarHidden = true - getWeatherInfo() - bindVC() - setDelegate() - addView() - } - private func addView() { - view.addSubview(locationView) - locationView.snp.makeConstraints { - $0.edges.equalTo(view.safeAreaLayoutGuide) - } + override func loadView() { + self.view = locationListView } - private func setDelegate() { - locationView.searchBar.delegate = self - locationView.weatherTableView.dataSource = self - locationView.weatherTableView.delegate = self - } - private func bindVC(){ - - for i in 0.. Int { - return infoList.count + return 4 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: WeatherListTableViewCell.cellReuseIdentifier, for: indexPath) as! WeatherListTableViewCell - cell.weatherData = infoList[indexPath.row] + // cell.weatherData = infoList[indexPath.row] cell.selectionStyle = .none return cell } diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/HeaderView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/HeaderView.swift deleted file mode 100644 index 007b21a..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/HeaderView.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// HeaderView.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/11/10. -// - -import UIKit - -class HeaderView: UICollectionReusableView { - static var reuseId = "HeaderView" - - override init(frame: CGRect) { - super.init(frame: frame) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SummaryCollectionViewCell.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeatherTimeHeaderView.swift similarity index 71% rename from SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SummaryCollectionViewCell.swift rename to SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeatherTimeHeaderView.swift index bcfa050..e9a29d4 100644 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SummaryCollectionViewCell.swift +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeatherTimeHeaderView.swift @@ -1,18 +1,25 @@ // -// SummaryCollectionViewCell.swift +// HeaderView.swift // SOPTWeather // -// Created by 지희의 MAC on 2023/11/10. +// Created by 지희의 MAC on 12/11/23. // import UIKit -class SummaryCollectionViewCell: UICollectionViewCell { +import SnapKit + +final class WeatherTimeHeaderView: UITableViewHeaderFooterView { + // MARK: - Variables + // MARK: Const + static var reuseId = "WeatherTimeHeaderView" + // MARK: Component private let cityTitleLabel: UILabel = { let label = UILabel() label.font = .sfProRegular36 label.textColor = .white + label.text = "고양시" return label }() @@ -20,6 +27,7 @@ class SummaryCollectionViewCell: UICollectionViewCell { let label = UILabel() label.font = .sfProThin102 label.textColor = .white + label.text = "0℃" return label }() @@ -27,6 +35,7 @@ class SummaryCollectionViewCell: UICollectionViewCell { let label = UILabel() label.font = .sfProRegular24 label.textColor = .white + label.text = "맑음" return label }() @@ -34,6 +43,7 @@ class SummaryCollectionViewCell: UICollectionViewCell { let label = UILabel() label.font = .sfProMedium20 label.textColor = .white + label.text = "최대 0℃ 최소 -12℃" return label }() @@ -49,25 +59,19 @@ class SummaryCollectionViewCell: UICollectionViewCell { return stackView }() - override init(frame: CGRect) { - super.init(frame: frame) + + // MARK: - Function + // MARK: LifeCycle + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) setUI() } - required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - - func setData(city: String, temp: String, weather: String, maxMin: String) { - self.cityTitleLabel.text = city - self.tempTitleLabel.text = temp - self.weatherLabel.text = weather - self.maxMinTempLabel.text = maxMin - } - - + // MARK: Layout Helpers private func setUI(){ setViewHierarchy() setConstraints() @@ -78,12 +82,16 @@ class SummaryCollectionViewCell: UICollectionViewCell { } private func setConstraints() { + weatherStackView.snp.makeConstraints { $0.center.equalToSuperview() } } -} - -extension SummaryCollectionViewCell: CollectionViewCellReuseProtocol { + func setData (city: String, temp: String, weather: String, maxmin: String) { + self.cityTitleLabel.text = city + self.tempTitleLabel.text = temp + self.weatherLabel.text = weather + self.maxMinTempLabel.text = maxmin + } } diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift new file mode 100644 index 0000000..0353aa2 --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift @@ -0,0 +1,68 @@ +// +// WeekHeaderView.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/12/23. +// + +import UIKit + +import SnapKit + +final class WeekHeaderView: UITableViewHeaderFooterView { + // MARK: - Variables + // MARK: Const + static var reuseId = "WeekHeaderView" + + // MARK: Component + private let titleLabel: UILabel = { + let label = UILabel() + label.font = .sfProMedium15 + label.text = "10일간의 일기예보" + label.textColor = .darkGray + return label + }() + + private let iconImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(systemName: "calendar")?.withTintColor(.darkGray, renderingMode: .alwaysOriginal) + return imageView + }() + + private lazy var titleStackView : UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 5 + stackView.addArrangeSubViews(iconImageView, titleLabel) + return stackView + }() + + + // MARK: - Function + // MARK: LifeCycle + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + setUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: Layout Helpers + private func setUI(){ + setViewHierarchy() + setConstraints() + } + + private func setViewHierarchy() { + self.addSubViews(titleStackView) + } + + private func setConstraints() { + titleStackView.snp.makeConstraints { + $0.top.equalToSuperview().offset(8) + $0.leading.equalToSuperview().offset(15) + } + } +} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SectionBackgroundView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SectionBackgroundView.swift deleted file mode 100644 index 6c70eef..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/SectionBackgroundView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// HeaderView.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/11/10. -// - -import UIKit - -class SectionBackgroundView: UICollectionReusableView { - private let backgroundView: UIView = { - let view = UIView() - view.backgroundColor = .clear - view.layer.borderColor = UIColor.white.cgColor - view.layer.borderWidth = 0.5 - view.layer.cornerRadius = 15 - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .clear - addSubview(backgroundView) - - backgroundView.snp.makeConstraints { - $0.top.bottom.equalToSuperview() - $0.leading.trailing.equalToSuperview().inset(10) - } - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift new file mode 100644 index 0000000..33a4c90 --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift @@ -0,0 +1,95 @@ +// +// TimeWeatherTableViewCell.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/12/23. +// + +import UIKit + +class TimeWeatherTableViewCell: UITableViewCell { + + static let reuseId = "TimeWeatherTableViewCell" + + var detailLabel: UILabel = { + let label = UILabel() + label.text = "08:00~09:00에 강우 상태가, 18:00에 한때 흐린 상태가 예상됩니다." + label.font = .sfProRegular18 + label.textColor = .white + label.numberOfLines = 3 + return label + }() + + lazy var timeWeatherCollectionView: UICollectionView = { + let flowLayout = UICollectionViewFlowLayout() + flowLayout.itemSize = CGSize(width: 44, height: 100) + flowLayout.minimumInteritemSpacing = 10 + flowLayout.scrollDirection = .horizontal + flowLayout.sectionInset = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20) + + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) + collectionView.register(TimeWeatherCollectionViewCell.self, forCellWithReuseIdentifier: TimeWeatherCollectionViewCell.reuseIdentifier) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.backgroundColor = .clear + collectionView.showsHorizontalScrollIndicator = false + return collectionView + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setUI() + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setUI(){ + setViewHierarchy() + setConstraints() + } + + private func setViewHierarchy() { + + self.backgroundColor = .clear + self.contentView.backgroundColor = .white.withAlphaComponent(0.1) + self.contentView.layer.cornerRadius = 20 + self.contentView.addSubViews(detailLabel, timeWeatherCollectionView) + } + + private func setConstraints() { + + detailLabel.snp.makeConstraints { + $0.top.equalToSuperview().offset(10) + $0.width.equalTo(340) + $0.centerX.equalToSuperview() + } + + timeWeatherCollectionView.snp.makeConstraints { + $0.top.equalTo(detailLabel.snp.bottom).offset(5) + $0.leading.trailing.bottom.equalToSuperview() + $0.height.equalTo(140) + } + } + +} + +extension TimeWeatherTableViewCell: UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return cityWeatherList[0].weatherinfomation.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeWeatherCollectionViewCell.reuseIdentifier, for: indexPath) as? TimeWeatherCollectionViewCell else { return UICollectionViewCell() } + cell.setData(time: cityWeatherList[0].weatherinfomation[indexPath.item].time, icon: cityWeatherList[0].weatherinfomation[indexPath.item].weatherIconImage, temp: cityWeatherList[0].weatherinfomation[indexPath.item].tempText) + return cell + } + + +} + +extension TimeWeatherTableViewCell: UICollectionViewDelegate { + +} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeekWeatherTableViewCell.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeekWeatherTableViewCell.swift new file mode 100644 index 0000000..0fa619c --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeekWeatherTableViewCell.swift @@ -0,0 +1,106 @@ +// +// WeekWeatherTableViewCell.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/12/23. +// + +import UIKit + +class WeekWeatherTableViewCell: UITableViewCell { + + static let reuseId = "WeekWeatherTableViewCell" + + private let weekLabel: UILabel = { + let label = UILabel() + label.font = .sfProMedium22 + label.textColor = .white + return label + }() + + private let WeathericonImageView: UIImageView = { + let imageView = UIImageView() + return imageView + }() + + private let precipitationLabel: UILabel = { + let label = UILabel() + label.font = .sfProMedium15 + label.textColor = .blue + return label + }() + + private lazy var weatherStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .center + stackView.addArrangeSubViews(WeathericonImageView, precipitationLabel) + return stackView + }() + + private let minTempLabel: UILabel = { + let label = UILabel() + label.font = .sfProMedium22 + label.textColor = .white.withAlphaComponent(0.3) + return label + }() + + private let gradientView: UIImageView = { + let imageView = UIImageView() + return imageView + }() + + private let maxTempLabel: UILabel = { + let label = UILabel() + label.font = .sfProMedium22 + label.textColor = .white + return label + }() + + private lazy var horizontalStackView : UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.alignment = .center + stackView.distribution = .equalCentering + stackView.addArrangeSubViews(weekLabel,weatherStackView,minTempLabel,gradientView,maxTempLabel) + stackView.setCustomSpacing(10, after: minTempLabel) + stackView.setCustomSpacing(10, after: gradientView) + return stackView + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setUI() + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + func setData(week:String, icon: UIImage, min:String, gradient: UIImage, max: String) { + weekLabel.text = week + WeathericonImageView.image = icon + minTempLabel.text = min + gradientView.image = gradient + maxTempLabel.text = max + } + + private func setUI(){ + setViewHierarchy() + setConstraints() + } + + private func setViewHierarchy() { + self.backgroundColor = .clear + self.addSubViews(horizontalStackView) + } + + private func setConstraints() { + horizontalStackView.snp.makeConstraints { + $0.center.equalToSuperview() + } + } + +} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/CityWeatherDetailViewController.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/CityWeatherDetailViewController.swift new file mode 100644 index 0000000..8353b72 --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/CityWeatherDetailViewController.swift @@ -0,0 +1,46 @@ +// +// WeatherDetailViewController.swift +// SOPTWeather +// +// Created by 지희의 MAC on 2023/10/21. +// + +import UIKit + +import SnapKit + +class CityWeatherDetailViewController: UIViewController { + + let cityWeatherDeatilView = CityWeatherView() + var weatherData = (cityName: "", weatherText: "", maxminTemp: "", weatherinfomation: []) + + override func loadView() { + super.loadView() + self.view = cityWeatherDeatilView + } + + override func viewDidLoad() { + super.viewDidLoad() + addTarget() + } + + func addTarget() { + navigationController?.interactivePopGestureRecognizer?.isEnabled = true + navigationController?.interactivePopGestureRecognizer?.delegate = self + cityWeatherDeatilView.listButton.addTarget(self, action: #selector(tapListButton), for: .touchUpInside) + } + + func setDelegate() { + cityWeatherDeatilView.weatherTableView.delegate = self + } + + @objc func tapListButton() { + navigationController?.popViewController(animated: true) + } +} + +extension CityWeatherDetailViewController : UIGestureRecognizerDelegate { } + +extension CityWeatherDetailViewController: UITableViewDelegate { } + + diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/WeatherDetailViewController.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/WeatherDetailViewController.swift deleted file mode 100644 index 6654e00..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewControllers/WeatherDetailViewController.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// WeatherDetailViewController.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/10/21. -// - -import UIKit - -import SnapKit - -class WeatherDetailViewController: UIViewController { - - - let weeklyWeatherData: [DayWeatherModel] = [DayWeatherModel(day: "오늘", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "15°", maxTempText: "29°", gradientImage: ImageLiterals.todayTempGradient), - DayWeatherModel(day: "월", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.oneDayTempGradient), - DayWeatherModel(day: "화", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "20°", maxTempText: "25°", gradientImage: ImageLiterals.twoDayTempGradient), - DayWeatherModel(day: "수", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "17°", maxTempText: "25°", gradientImage: ImageLiterals.threeDayTempGradient), - DayWeatherModel(day: "목", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.fourDayTempGradient), - DayWeatherModel(day: "금", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.fiveDayTempGradient), - DayWeatherModel(day: "토", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.sixDayTempGradient), - DayWeatherModel(day: "일", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.sevenDayTempGradient), - DayWeatherModel(day: "월", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.eightDayTempGradient), - DayWeatherModel(day: "화", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.nineDayTempGradient), - DayWeatherModel(day: "수", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.tenDayTempGradient) - ] - - - let weatherDetailView = WeatherDetailView() - let cityWeatherDeatilView = CityWeatherDetailView() - var weatherData = (cityName: "", weatherText: "", maxminTemp: "", weatherinfomation: []) - - override func viewDidLoad() { - super.viewDidLoad() - setView() - addTarget() - } - - func setView() { - cityWeatherDeatilView.detailWeatherData = weatherData - cityWeatherDeatilView.weekWeatherData = weeklyWeatherData - - view.addSubview(cityWeatherDeatilView) - - cityWeatherDeatilView.snp.makeConstraints { - $0.edges.equalToSuperview() - } - } - - func addTarget() { - navigationController?.interactivePopGestureRecognizer?.isEnabled = true - navigationController?.interactivePopGestureRecognizer?.delegate = self - cityWeatherDeatilView.listButton.addTarget(self, action: #selector(tapListButton), for: .touchUpInside) - } - - func setDelegate() { - cityWeatherDeatilView.collectionView.delegate = self - } - - @objc func tapListButton() { - navigationController?.popViewController(animated: true) - } -} - -extension WeatherDetailViewController : UIGestureRecognizerDelegate { } - -extension WeatherDetailViewController: UICollectionViewDelegate { } - - diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherDetailView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherDetailView.swift deleted file mode 100644 index fc64056..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherDetailView.swift +++ /dev/null @@ -1,262 +0,0 @@ -// -// CityWeatherDetailView.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/11/08. -// - -import UIKit - -import SnapKit - -class CityWeatherDetailView: UIView { - // MARK: - Variables - // MARK: Property - var detailWeatherData: = (cityName: "", weatherText: "", maxminTemp: "", weatherinfomation: []) - var weekWeatherData: [DayWeatherModel] = [] - - // MARK: Component - private let backgroundImageView: UIImageView = { - let imageView = UIImageView() - imageView.image = ImageLiterals.backgroundFull - return imageView - }() - - let mapButton: UIButton = { - let button = UIButton() - button.setImage(ImageLiterals.mapIcon, for: .normal) - button.tintColor = .white - return button - }() - - let listButton: UIButton = { - let button = UIButton() - button.setImage(ImageLiterals.listIcon, for: .normal) - button.tintColor = .white - return button - }() - - lazy var collectionView: UICollectionView = { - let flowLayout = createLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) - collectionView.isScrollEnabled = true - collectionView.backgroundColor = .clear - - flowLayout.register(SectionBackgroundView.self, forDecorationViewOfKind: "background") - - collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: HeaderView.reuseId) - - SummaryCollectionViewCell.register(collectionView: collectionView) - TimeWeatherCollectionViewCell.register(collectionView: collectionView) - WeeklyWeatherCollectionViewCell.register(collectionView: collectionView) - collectionView.dataSource = self - return collectionView - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - private func setUI(){ - setViewHierarchy() - setConstraints() - } - - private func setViewHierarchy() { - self.addSubViews(backgroundImageView, - collectionView, - mapButton, - listButton) - } - - private func setConstraints() { - - backgroundImageView.snp.makeConstraints { - $0.edges.equalToSuperview() - } - - collectionView.snp.makeConstraints { - $0.top.equalToSuperview().offset(34) - $0.leading.trailing.bottom.equalToSuperview() - } - - mapButton.snp.makeConstraints { - $0.bottom.equalToSuperview().inset(34) - $0.leading.equalToSuperview().inset(16) - } - - listButton.snp.makeConstraints { - $0.bottom.equalToSuperview().inset(34) - $0.trailing.equalToSuperview().inset(16) - } - } - - private func createMainLayout() -> NSCollectionLayoutSection { - let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(self.bounds.width), heightDimension: .absolute(212)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - // group설정 - let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(250)) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 1) - // section 설정 - let section = NSCollectionLayoutSection(group: group) - //스크롤 설정 - section.orthogonalScrollingBehavior = .paging - - return section - } - - - private func createTimeLayout() -> NSCollectionLayoutSection { - // 각 item의 사이즈 설정 - let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(44), heightDimension: .absolute(122)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - item.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 34, bottom: 10, trailing: 34) - - // group설정 - let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(144)) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) - group.interItemSpacing = NSCollectionLayoutSpacing.fixed(22) - - // section 설정 - let section = NSCollectionLayoutSection(group: group) - - - //헤더뷰 레이아웃 - section.boundarySupplementaryItems = [.init(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)), elementKind: UICollectionView.elementKindSectionHeader, alignment: .topLeading)] - section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 24, bottom: 20, trailing: 24) - - - // Background - let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background(elementKind: "background") - section.decorationItems = [sectionBackgroundDecoration] - - //스크롤 설정 - section.orthogonalScrollingBehavior = .continuous - - return section - } - - private func createWeekLayout() -> NSCollectionLayoutSection { - let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(self.bounds.width), heightDimension: .absolute(55)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - - let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) - let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item]) - - let section = NSCollectionLayoutSection(group: group) - - section.orthogonalScrollingBehavior = .none - - section.boundarySupplementaryItems = [.init(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)), elementKind: UICollectionView.elementKindSectionHeader, alignment: .topLeading)] - - return section - } - - private func createLayout() -> UICollectionViewCompositionalLayout { - return UICollectionViewCompositionalLayout {[weak self] sectionNumber, env -> NSCollectionLayoutSection? in - - switch sectionNumber { - case 0: - return self?.createMainLayout() - case 1: - return self?.createTimeLayout() - default: - return self?.createWeekLayout() - } - } - } - -} - -extension CityWeatherDetailView: UICollectionViewDataSource { - - func numberOfSections(in collectionView: UICollectionView) -> Int { - return 3 - } - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - switch section { - case 0: - return 1 - case 1: - return detailWeatherData.weatherinfomation.count - case 2: - return weekWeatherData.count - default: - return 1 - } - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if indexPath.section == 0 { - let cell = SummaryCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) - - cell.setData(city: detailWeatherData.cityName, temp: detailWeatherData.weatherinfomation[0].tempText, weather: detailWeatherData.weatherText, maxMin: detailWeatherData.maxminTemp) - return cell - - } else if indexPath.section == 1 { - let cell = TimeWeatherCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) - cell.setData(time: detailWeatherData.weatherinfomation[indexPath.row].time, - icon: detailWeatherData.weatherinfomation[indexPath.row].weatherIconImage, - temp: detailWeatherData.weatherinfomation[indexPath.row].tempText) - return cell - - } else if indexPath.section == 2 { - let cell = WeeklyWeatherCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) - cell.setData(week: weekWeatherData[indexPath.row].day, icon: weekWeatherData[indexPath.row].weatherIconImage, min: weekWeatherData[indexPath.row].minTempText, gradient: weekWeatherData[indexPath.row].gradientImage, max: weekWeatherData[indexPath.row].maxTempText) - return cell - } - - return UICollectionViewCell() - } - - func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - if kind == UICollectionView.elementKindSectionHeader { - let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HeaderView.reuseId, for: indexPath) as! HeaderView - if indexPath.section == 1 { - - let label = UILabel() - label.text = "08:00~09:00에 강우 상태가, 18:00에 한때 흐린 상태가 예상됩니다." - label.font = .sfProRegular18 - label.textColor = .white - label.numberOfLines = 3 - - headerView.addSubview(label) - - // 레이블의 제약조건 설정 (예: 스냅킷 라이브러리 사용) - label.snp.makeConstraints { - $0.top.equalToSuperview().inset(15) - $0.leading.trailing.equalToSuperview().inset(16) - } - - } else if indexPath.section == 2 { - let iconImageView = UIImageView(image: UIImage(systemName: "calendar")?.withTintColor(.white.withAlphaComponent(0.3), renderingMode: .alwaysOriginal)) - - - let label = UILabel() - label.text = "10일간의 일기예보" - label.font = .sfProMedium15 - label.textColor = .white.withAlphaComponent(0.3) - headerView.addSubViews(iconImageView, label) - - iconImageView.snp.makeConstraints { - $0.top.equalToSuperview().offset(15) - $0.leading.equalToSuperview().offset(15) - $0.size.equalTo(24) - } - - label.snp.makeConstraints { - $0.centerY.equalTo(iconImageView) - $0.leading.equalTo(iconImageView.snp.trailing).offset(5) - } - } - return headerView - } - return UICollectionReusableView() - } - -} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift new file mode 100644 index 0000000..1b075d1 --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift @@ -0,0 +1,147 @@ +// +// WeatherDetail.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/11/23. +// + +import UIKit + +import SnapKit + +final class CityWeatherView: UIView { + // MARK: - Variables + // MARK: Constants + let viewModel = WeatherDetailViewModel() + + // MARK: Property + + + // MARK: Component + private let backgroundImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = ImageLiterals.backgroundFull + return imageView + }() + + let mapButton: UIButton = { + let button = UIButton() + button.setImage(ImageLiterals.mapIcon, for: .normal) + button.tintColor = .white + return button + }() + + let listButton: UIButton = { + let button = UIButton() + button.setImage(ImageLiterals.listIcon, for: .normal) + button.tintColor = .white + return button + }() + + lazy var weatherTableView: UITableView = { + let tableView = UITableView(frame: .zero, style: .grouped) + tableView.backgroundColor = .clear + tableView.register(WeatherTimeHeaderView.self, forHeaderFooterViewReuseIdentifier: WeatherTimeHeaderView.reuseId) + tableView.register(WeekHeaderView.self, forHeaderFooterViewReuseIdentifier: WeekHeaderView.reuseId) + tableView.register(TimeWeatherTableViewCell.self, forCellReuseIdentifier: TimeWeatherTableViewCell.reuseId) + tableView.register(WeekWeatherTableViewCell.self, forCellReuseIdentifier: WeekWeatherTableViewCell.reuseId) + return tableView + }() + + // MARK: - Functio + // MARK: LifeCycle + override init(frame: CGRect) { + super.init(frame: frame) + setUI() + bindViewModel() + setDelegate() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: Layout Helpers + private func setUI(){ + setViewHierarchy() + setConstraints() + } + + private func setViewHierarchy() { + self.addSubViews(backgroundImageView, weatherTableView, listButton, mapButton) + } + + private func setConstraints() { + backgroundImageView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + weatherTableView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + listButton.snp.makeConstraints { + $0.leading.equalToSuperview().offset(28) + $0.bottom.equalToSuperview().inset(32) + } + + mapButton.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(28) + $0.bottom.equalTo(listButton.snp.bottom) + } + } + + // MARK: Custom Function + func setDelegate() { + self.weatherTableView.delegate = self + } + + func bindViewModel() { + self.weatherTableView.dataSource = viewModel + } + + // MARK: Objc Function + + +} + + +extension CityWeatherView: UITableViewDelegate { + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + switch section { + case 0: + let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: WeatherTimeHeaderView.reuseId) as? WeatherTimeHeaderView + return header + case 1: + let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: WeekHeaderView.reuseId) as? WeekHeaderView + return header + default: + let header = UIView() + return header + } + + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + switch section { + case 0: + return 280 + case 1: + return 40 + default: + return 0 + } + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + switch indexPath.section { + case 0: + return 212 + case 1: + return 55 + default: + return 0 + } + } + +} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/TimeWeatherView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/TimeWeatherView.swift deleted file mode 100644 index e5a936a..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/TimeWeatherView.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// TimeWeatherView.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/10/26. -// - -import UIKit - -import SnapKit - -class TimeWeatherView: UIView { - // MARK: - Variables - // MARK: Constants - - // MARK: Property - - // MARK: Component - private let timeLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium17 - label.textColor = .white - return label - }() - - private let iconImageView: UIImageView = { - let imageView = UIImageView() - imageView.tintColor = .white - imageView.contentMode = .scaleAspectFit - return imageView - }() - - private let tempLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium22 - label.textColor = .white - return label - }() - - - override init(frame: CGRect) { - super.init(frame: frame) - setUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - init(time: String, iconImage: UIImage, temp: String) { - super.init(frame: .zero) - self.timeLabel.text = time - self.iconImageView.image = iconImage.withAlignmentRectInsets(UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)) - self.tempLabel.text = temp - setUI() - } - - private func setUI(){ - setViewHierarchy() - setConstraints() - } - - private func setViewHierarchy() { - self.addSubViews(timeLabel,iconImageView,tempLabel) - } - - private func setConstraints() { - self.snp.makeConstraints { - $0.width.equalTo(44) - } - - timeLabel.snp.makeConstraints { - $0.top.equalToSuperview() - $0.centerX.equalToSuperview() - } - - iconImageView.snp.makeConstraints { - $0.top.equalTo(timeLabel.snp.bottom).offset(14) - $0.centerX.equalToSuperview() - $0.size.equalTo(44) - } - - tempLabel.snp.makeConstraints { - $0.top.equalTo(iconImageView.snp.bottom).offset(14) - $0.centerX.equalToSuperview() - } - } -} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/WeatherDetailView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/WeatherDetailView.swift deleted file mode 100644 index 4f60a75..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/WeatherDetailView.swift +++ /dev/null @@ -1,226 +0,0 @@ -// -// WeatherDetailView.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/10/21. -// - -import UIKit -import SnapKit - -class WeatherDetailView: UIView { - - // MARK: - Variables - // MARK: Property - private var detailWeatherList: [TimeWeatherModel] = [] - - // MARK: Component - let scrollView: UIScrollView = { - let scrollView = UIScrollView() - scrollView.alwaysBounceVertical = true - return scrollView - }() - - private let backgroundImageView: UIImageView = { - let imageView = UIImageView() - imageView.image = ImageLiterals.backgroundFull - return imageView - }() - - private let cityTitleLabel: UILabel = { - let label = UILabel() - label.font = .sfProRegular36 - label.textColor = .white - return label - }() - - private let tempTitleLabel: UILabel = { - let label = UILabel() - label.font = .sfProThin102 - label.textColor = .white - return label - }() - - private let weatherLabel: UILabel = { - let label = UILabel() - label.font = .sfProRegular24 - label.textColor = .white - return label - }() - - private let maxMinTempLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium20 - label.textColor = .white - return label - }() - - private lazy var weatherStackView : UIStackView = { - let stackView = UIStackView() - stackView.addArrangeSubViews(cityTitleLabel, - tempTitleLabel, - weatherLabel, - maxMinTempLabel) - stackView.spacing = 4 - stackView.alignment = .center - stackView.axis = .vertical - return stackView - }() - - - private let weatherDetailLabel: UILabel = { - let label = UILabel() - label.font = .sfProRegular18 - label.textColor = .white - label.numberOfLines = 3 - label.text = "08:00~09:00에 강우 상태가, 18:00에 한때 흐린 상태가 예상됩니다." - return label - }() - - private let lineView: UIView = { - let view = UIView() - view.backgroundColor = .darkGray - return view - }() - - private let timeWeatherScrollView: UIScrollView = { - let scrollView = UIScrollView() - scrollView.showsHorizontalScrollIndicator = false - return scrollView - }() - - private lazy var weatherDetailStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.spacing = 11 - stackView.addArrangeSubViews(weatherDetailLabel, - lineView, - timeWeatherScrollView) - stackView.layer.cornerRadius = 15 - stackView.layer.borderWidth = 1 - stackView.layer.borderColor = UIColor.darkGray.cgColor - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15) - stackView.frame = CGRect(x: 0, y: 0, width: 335, height: 212) - - return stackView - }() - - private lazy var timeStackView: UIStackView = { - let stackView = UIStackView() - stackView.spacing = 22 - return stackView - }() - - let mapButton: UIButton = { - let button = UIButton() - button.setImage(ImageLiterals.mapIcon, for: .normal) - button.tintColor = .white - return button - }() - - let listButton: UIButton = { - let button = UIButton() - button.setImage(ImageLiterals.listIcon, for: .normal) - button.tintColor = .white - return button - }() - - - // MARK: - Function - // MARK: Init - override init(frame: CGRect) { - super.init(frame: frame) - setUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: Layout Helpers - private func setUI(){ - setViewHierarchy() - setConstraints() - } - - private func setViewHierarchy() { - - self.addSubViews(backgroundImageView,scrollView, - mapButton, - listButton) - - scrollView.addSubViews(weatherStackView, - weatherDetailStackView) - - timeWeatherScrollView.addSubview(timeStackView) - - for i in 0.. Int { + switch section { + case 0: + return 1 + case 1: + return 10 + default: + return 0 + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = UITableViewCell() + if indexPath.section == 0 { + guard let cell = tableView.dequeueReusableCell(withIdentifier: TimeWeatherTableViewCell.reuseId, for: indexPath) as? TimeWeatherTableViewCell else { return cell } + cell.selectionStyle = .none + return cell + } else if indexPath.section == 1 { + guard let cell = tableView.dequeueReusableCell(withIdentifier: WeekWeatherTableViewCell.reuseId, for: indexPath) as? WeekWeatherTableViewCell else { return cell } + cell.setData(week: weeklyWeatherData[indexPath.row].day , icon: weeklyWeatherData[indexPath.row].weatherIconImage, min: weeklyWeatherData[indexPath.row].minTempText, gradient: weeklyWeatherData[indexPath.row].gradientImage, max: weeklyWeatherData[indexPath.row].maxTempText) + cell.selectionStyle = .none + return cell + } + return cell + } + + func numberOfSections(in tableView: UITableView) -> Int { + return 2 + } + + +} + + + + +// +//extension CityWeatherDetailView: UICollectionViewDataSource { +// +// func numberOfSections(in collectionView: UICollectionView) -> Int { +// return 3 +// } +// +// func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { +// switch section { +// case 0: +// return 1 +// case 1: +// return detailWeatherData.weatherinfomation.count +// case 2: +// return weekWeatherData.count +// default: +// return 1 +// } +// } +// +// func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { +// if indexPath.section == 0 { +// let cell = SummaryCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) +// +// cell.setData(city: detailWeatherData.cityName, temp: detailWeatherData.weatherinfomation[0].tempText, weather: detailWeatherData.weatherText, maxMin: detailWeatherData.maxminTemp) +// return cell +// +// } else if indexPath.section == 1 { +// let cell = TimeWeatherCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) +// cell.setData(time: detailWeatherData.weatherinfomation[indexPath.row].time, +// icon: detailWeatherData.weatherinfomation[indexPath.row].weatherIconImage, +// temp: detailWeatherData.weatherinfomation[indexPath.row].tempText) +// return cell +// +// } else if indexPath.section == 2 { +// let cell = WeeklyWeatherCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) +// cell.setData(week: weekWeatherData[indexPath.row].day, icon: weekWeatherData[indexPath.row].weatherIconImage, min: weekWeatherData[indexPath.row].minTempText, gradient: weekWeatherData[indexPath.row].gradientImage, max: weekWeatherData[indexPath.row].maxTempText) +// return cell +// } +// +// return UICollectionViewCell() +// } +// +// func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { +// if kind == UICollectionView.elementKindSectionHeader { +// let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HeaderView.reuseId, for: indexPath) as! HeaderView +// if indexPath.section == 1 { +// +// let label = UILabel() +// label.text = "08:00~09:00에 강우 상태가, 18:00에 한때 흐린 상태가 예상됩니다." +// label.font = .sfProRegular18 +// label.textColor = .white +// label.numberOfLines = 3 +// +// headerView.addSubview(label) +// +// // 레이블의 제약조건 설정 (예: 스냅킷 라이브러리 사용) +// label.snp.makeConstraints { +// $0.top.equalToSuperview().inset(15) +// $0.leading.trailing.equalToSuperview().inset(16) +// } +// +// } else if indexPath.section == 2 { +// let iconImageView = UIImageView(image: UIImage(systemName: "calendar")?.withTintColor(.white.withAlphaComponent(0.3), renderingMode: .alwaysOriginal)) +// +// +// let label = UILabel() +// label.text = "10일간의 일기예보" +// label.font = .sfProMedium15 +// label.textColor = .white.withAlphaComponent(0.3) +// headerView.addSubViews(iconImageView, label) +// +// iconImageView.snp.makeConstraints { +// $0.top.equalToSuperview().offset(15) +// $0.leading.equalToSuperview().offset(15) +// $0.size.equalTo(24) +// } +// +// label.snp.makeConstraints { +// $0.centerY.equalTo(iconImageView) +// $0.leading.equalTo(iconImageView.snp.trailing).offset(5) +// } +// } +// return headerView +// } +// return UICollectionReusableView() +// } +// +//} From 883589496cd4b2d42fd59fc8880269dc484e5e5c Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 15 Dec 2023 23:45:14 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Chore/#5=20=EB=B7=B0=20=EB=94=94=ED=85=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cells/Helper/WeekHeaderView.swift | 17 ++++++++++-- .../Cells/TimeWeatherTableViewCell.swift | 27 +++++++++++++++---- .../WeatherDetail/Views/CityWeatherView.swift | 10 +++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift index 0353aa2..a542643 100644 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/Helper/WeekHeaderView.swift @@ -37,6 +37,13 @@ final class WeekHeaderView: UITableViewHeaderFooterView { return stackView }() + let backView: UIView = { + let view = UIView() + view.backgroundColor = .white.withAlphaComponent(0.02) + view.layer.cornerRadius = 20 + return view + }() + // MARK: - Function // MARK: LifeCycle @@ -56,12 +63,18 @@ final class WeekHeaderView: UITableViewHeaderFooterView { } private func setViewHierarchy() { - self.addSubViews(titleStackView) + + self.addSubViews(backView, titleStackView) } private func setConstraints() { + backView.snp.makeConstraints { + $0.top.equalToSuperview() + $0.leading.trailing.equalToSuperview().inset(10) + $0.height.equalTo(675) + } titleStackView.snp.makeConstraints { - $0.top.equalToSuperview().offset(8) + $0.top.equalToSuperview().offset(10) $0.leading.equalToSuperview().offset(15) } } diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift index 33a4c90..49eb173 100644 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/TimeWeatherTableViewCell.swift @@ -11,7 +11,7 @@ class TimeWeatherTableViewCell: UITableViewCell { static let reuseId = "TimeWeatherTableViewCell" - var detailLabel: UILabel = { + let detailLabel: UILabel = { let label = UILabel() label.text = "08:00~09:00에 강우 상태가, 18:00에 한때 흐린 상태가 예상됩니다." label.font = .sfProRegular18 @@ -20,6 +20,12 @@ class TimeWeatherTableViewCell: UITableViewCell { return label }() + let lineView: UIView = { + let view = UIView() + view.backgroundColor = .white + return view + }() + lazy var timeWeatherCollectionView: UICollectionView = { let flowLayout = UICollectionViewFlowLayout() flowLayout.itemSize = CGSize(width: 44, height: 100) @@ -54,22 +60,33 @@ class TimeWeatherTableViewCell: UITableViewCell { private func setViewHierarchy() { self.backgroundColor = .clear - self.contentView.backgroundColor = .white.withAlphaComponent(0.1) + self.contentView.backgroundColor = .white.withAlphaComponent(0.03) self.contentView.layer.cornerRadius = 20 - self.contentView.addSubViews(detailLabel, timeWeatherCollectionView) + self.contentView.addSubViews(detailLabel, lineView, timeWeatherCollectionView) } private func setConstraints() { + self.contentView.snp.makeConstraints { + $0.leading.trailing.equalToSuperview().inset(10) + } + detailLabel.snp.makeConstraints { $0.top.equalToSuperview().offset(10) $0.width.equalTo(340) $0.centerX.equalToSuperview() } + lineView.snp.makeConstraints { + $0.top.equalTo(detailLabel.snp.bottom).offset(11) + $0.leading.trailing.equalToSuperview().inset(10) + $0.height.equalTo(0.2) + } + timeWeatherCollectionView.snp.makeConstraints { - $0.top.equalTo(detailLabel.snp.bottom).offset(5) - $0.leading.trailing.bottom.equalToSuperview() + $0.top.equalTo(lineView.snp.bottom).offset(11) + $0.leading.trailing.equalToSuperview() + $0.bottom.equalToSuperview().inset(10) $0.height.equalTo(140) } } diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift index 1b075d1..144505c 100644 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Views/CityWeatherView.swift @@ -144,4 +144,14 @@ extension CityWeatherView: UITableViewDelegate { } } + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + switch section { + case 0 : + return 30 + case 1: + return 10 + default: + return 0 + } + } } From 04e9891aa46eeb558105bef848b25b68058330ac Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 15 Dec 2023 23:45:28 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Chore/#5=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SOPTWeather.xcodeproj/project.pbxproj | 14 +- .../WeeklyWeatherCollectionViewCell.swift | 106 ------------ .../ViewModel/WeatherDetailViewModel.swift | 59 +++++++ .../WeatherDetailViewModel.swift | 152 ------------------ 4 files changed, 68 insertions(+), 263 deletions(-) delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeeklyWeatherCollectionViewCell.swift create mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewModel/WeatherDetailViewModel.swift delete mode 100644 SOPTWeather/SOPTWeather/Presentation/WeatherDetail/WeatherDetailViewModel.swift diff --git a/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj b/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj index 301626f..d44b065 100644 --- a/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj +++ b/SOPTWeather/SOPTWeather.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 3651D8BD2B20639600BE0699 /* LocationListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */; }; 3651D8BF2B21074F00BE0699 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3651D8BE2B21074F00BE0699 /* Observable.swift */; }; 366014932AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */; }; - 366014952AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */; }; 366014972AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366014962AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift */; }; 3660149D2AFE1E9B00D3D4F7 /* UIImage+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3660149C2AFE1E9B00D3D4F7 /* UIImage+.swift */; }; 366646612B03715B006C8B5E /* WeatherModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366646602B03715B006C8B5E /* WeatherModel.swift */; }; @@ -53,7 +52,6 @@ 3651D8BC2B20639600BE0699 /* LocationListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationListViewModel.swift; sourceTree = ""; }; 3651D8BE2B21074F00BE0699 /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeWeatherCollectionViewCell.swift; sourceTree = ""; }; - 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeeklyWeatherCollectionViewCell.swift; sourceTree = ""; }; 366014962AFB7DF700D3D4F7 /* CollectionViewCellReuseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewCellReuseProtocol.swift; sourceTree = ""; }; 3660149C2AFE1E9B00D3D4F7 /* UIImage+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+.swift"; sourceTree = ""; }; 366646602B03715B006C8B5E /* WeatherModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherModel.swift; sourceTree = ""; }; @@ -119,7 +117,6 @@ children = ( 36CC2C3F2B274EAE0066B942 /* Helper */, 366014922AFB73F300D3D4F7 /* TimeWeatherCollectionViewCell.swift */, - 366014942AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift */, 36CC2C402B2761F00066B942 /* TimeWeatherTableViewCell.swift */, 36CC2C422B276E370066B942 /* WeekWeatherTableViewCell.swift */, ); @@ -152,6 +149,14 @@ path = Helper; sourceTree = ""; }; + 36CC2C4B2B2C973D0066B942 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 36CC2C462B2770BC0066B942 /* WeatherDetailViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 36E60E342AE180F9005035D3 = { isa = PBXGroup; children = ( @@ -291,10 +296,10 @@ 36E60E872AE2EC7D005035D3 /* WeatherDetail */ = { isa = PBXGroup; children = ( + 36CC2C4B2B2C973D0066B942 /* ViewModel */, 3660149A2AFE0E0D00D3D4F7 /* ViewControllers */, 3660149B2AFE0E1500D3D4F7 /* Views */, 366014912AFB739B00D3D4F7 /* Cells */, - 36CC2C462B2770BC0066B942 /* WeatherDetailViewModel.swift */, ); path = WeatherDetail; sourceTree = ""; @@ -436,7 +441,6 @@ 36E60E732AE2595D005035D3 /* Font.swift in Sources */, 36CC2C3A2B2742360066B942 /* CityWeatherView.swift in Sources */, 3651D8BD2B20639600BE0699 /* LocationListViewModel.swift in Sources */, - 366014952AFB740000D3D4F7 /* WeeklyWeatherCollectionViewCell.swift in Sources */, 366646612B03715B006C8B5E /* WeatherModel.swift in Sources */, 36E60E772AE25975005035D3 /* ImageLiterals.swift in Sources */, 36E60E8D2AE2F0C6005035D3 /* CityWeatherDetailViewController.swift in Sources */, diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeeklyWeatherCollectionViewCell.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeeklyWeatherCollectionViewCell.swift deleted file mode 100644 index 7457544..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/Cells/WeeklyWeatherCollectionViewCell.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// WeeklyWeatherCollectionViewCell.swift -// SOPTWeather -// -// Created by 지희의 MAC on 2023/11/08. -// - -import UIKit - -class WeeklyWeatherCollectionViewCell: UICollectionViewCell { - - - private let weekLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium22 - label.textColor = .white - return label - }() - - private let WeathericonImageView: UIImageView = { - let imageView = UIImageView() - return imageView - }() - - private let precipitationLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium15 - label.textColor = .blue - return label - }() - - private lazy var weatherStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.addArrangeSubViews(WeathericonImageView, precipitationLabel) - return stackView - }() - - private let minTempLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium22 - label.textColor = .white.withAlphaComponent(0.3) - return label - }() - - private let gradientView: UIImageView = { - let imageView = UIImageView() - return imageView - }() - - private let maxTempLabel: UILabel = { - let label = UILabel() - label.font = .sfProMedium22 - label.textColor = .white - return label - }() - - private lazy var horizontalStackView : UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.alignment = .center - stackView.distribution = .equalCentering - stackView.addArrangeSubViews(weekLabel,weatherStackView,minTempLabel,gradientView,maxTempLabel) - stackView.setCustomSpacing(10, after: minTempLabel) - stackView.setCustomSpacing(10, after: gradientView) - return stackView - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setData(week:String, icon: UIImage, min:String, gradient: UIImage, max: String) { - weekLabel.text = week - WeathericonImageView.image = icon - minTempLabel.text = min - gradientView.image = gradient - maxTempLabel.text = max - } - - private func setUI(){ - setViewHierarchy() - setConstraints() - } - - private func setViewHierarchy() { - self.addSubViews(horizontalStackView) - } - - private func setConstraints() { - horizontalStackView.snp.makeConstraints { - $0.center.equalToSuperview() - } - } - -} - -extension WeeklyWeatherCollectionViewCell: CollectionViewCellReuseProtocol { - -} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewModel/WeatherDetailViewModel.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewModel/WeatherDetailViewModel.swift new file mode 100644 index 0000000..ea52b19 --- /dev/null +++ b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/ViewModel/WeatherDetailViewModel.swift @@ -0,0 +1,59 @@ +// +// WeatherDetailViewModel.swift +// SOPTWeather +// +// Created by 지희의 MAC on 12/12/23. +// + +import UIKit + +class WeatherDetailViewModel: NSObject { + + let weeklyWeatherData: [DayWeatherModel] = [DayWeatherModel(day: "오늘", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "15°", maxTempText: "29°", gradientImage: ImageLiterals.todayTempGradient), + DayWeatherModel(day: "월", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.oneDayTempGradient), + DayWeatherModel(day: "화", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "20°", maxTempText: "25°", gradientImage: ImageLiterals.twoDayTempGradient), + DayWeatherModel(day: "수", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "17°", maxTempText: "25°", gradientImage: ImageLiterals.threeDayTempGradient), + DayWeatherModel(day: "목", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.fourDayTempGradient), + DayWeatherModel(day: "금", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.fiveDayTempGradient), + DayWeatherModel(day: "토", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.sixDayTempGradient), + DayWeatherModel(day: "일", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.sevenDayTempGradient), + DayWeatherModel(day: "월", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.eightDayTempGradient), + DayWeatherModel(day: "화", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.nineDayTempGradient), + DayWeatherModel(day: "수", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.tenDayTempGradient) + ] + +} + +extension WeatherDetailViewModel: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch section { + case 0: + return 1 + case 1: + return 10 + default: + return 0 + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = UITableViewCell() + if indexPath.section == 0 { + guard let cell = tableView.dequeueReusableCell(withIdentifier: TimeWeatherTableViewCell.reuseId, for: indexPath) as? TimeWeatherTableViewCell else { return cell } + cell.selectionStyle = .none + return cell + } else if indexPath.section == 1 { + guard let cell = tableView.dequeueReusableCell(withIdentifier: WeekWeatherTableViewCell.reuseId, for: indexPath) as? WeekWeatherTableViewCell else { return cell } + cell.setData(week: weeklyWeatherData[indexPath.row].day , icon: weeklyWeatherData[indexPath.row].weatherIconImage, min: weeklyWeatherData[indexPath.row].minTempText, gradient: weeklyWeatherData[indexPath.row].gradientImage, max: weeklyWeatherData[indexPath.row].maxTempText) + cell.selectionStyle = .none + return cell + } + return cell + } + + func numberOfSections(in tableView: UITableView) -> Int { + return 2 + } + + +} diff --git a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/WeatherDetailViewModel.swift b/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/WeatherDetailViewModel.swift deleted file mode 100644 index b687d47..0000000 --- a/SOPTWeather/SOPTWeather/Presentation/WeatherDetail/WeatherDetailViewModel.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// WeatherDetailViewModel.swift -// SOPTWeather -// -// Created by 지희의 MAC on 12/12/23. -// - -import UIKit - -class WeatherDetailViewModel: NSObject { - - let weeklyWeatherData: [DayWeatherModel] = [DayWeatherModel(day: "오늘", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "15°", maxTempText: "29°", gradientImage: ImageLiterals.todayTempGradient), - DayWeatherModel(day: "월", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.oneDayTempGradient), - DayWeatherModel(day: "화", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "20°", maxTempText: "25°", gradientImage: ImageLiterals.twoDayTempGradient), - DayWeatherModel(day: "수", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "17°", maxTempText: "25°", gradientImage: ImageLiterals.threeDayTempGradient), - DayWeatherModel(day: "목", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.fourDayTempGradient), - DayWeatherModel(day: "금", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.fiveDayTempGradient), - DayWeatherModel(day: "토", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.sixDayTempGradient), - DayWeatherModel(day: "일", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.sevenDayTempGradient), - DayWeatherModel(day: "월", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.eightDayTempGradient), - DayWeatherModel(day: "화", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.nineDayTempGradient), - DayWeatherModel(day: "수", weatherIconImage: ImageLiterals.sunIcon.withRenderingMode(.alwaysOriginal), minTempText: "18°", maxTempText: "27°", gradientImage: ImageLiterals.tenDayTempGradient) - ] - -} - -extension WeatherDetailViewModel: UITableViewDataSource { - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 0: - return 1 - case 1: - return 10 - default: - return 0 - } - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - if indexPath.section == 0 { - guard let cell = tableView.dequeueReusableCell(withIdentifier: TimeWeatherTableViewCell.reuseId, for: indexPath) as? TimeWeatherTableViewCell else { return cell } - cell.selectionStyle = .none - return cell - } else if indexPath.section == 1 { - guard let cell = tableView.dequeueReusableCell(withIdentifier: WeekWeatherTableViewCell.reuseId, for: indexPath) as? WeekWeatherTableViewCell else { return cell } - cell.setData(week: weeklyWeatherData[indexPath.row].day , icon: weeklyWeatherData[indexPath.row].weatherIconImage, min: weeklyWeatherData[indexPath.row].minTempText, gradient: weeklyWeatherData[indexPath.row].gradientImage, max: weeklyWeatherData[indexPath.row].maxTempText) - cell.selectionStyle = .none - return cell - } - return cell - } - - func numberOfSections(in tableView: UITableView) -> Int { - return 2 - } - - -} - - - - -// -//extension CityWeatherDetailView: UICollectionViewDataSource { -// -// func numberOfSections(in collectionView: UICollectionView) -> Int { -// return 3 -// } -// -// func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { -// switch section { -// case 0: -// return 1 -// case 1: -// return detailWeatherData.weatherinfomation.count -// case 2: -// return weekWeatherData.count -// default: -// return 1 -// } -// } -// -// func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { -// if indexPath.section == 0 { -// let cell = SummaryCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) -// -// cell.setData(city: detailWeatherData.cityName, temp: detailWeatherData.weatherinfomation[0].tempText, weather: detailWeatherData.weatherText, maxMin: detailWeatherData.maxminTemp) -// return cell -// -// } else if indexPath.section == 1 { -// let cell = TimeWeatherCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) -// cell.setData(time: detailWeatherData.weatherinfomation[indexPath.row].time, -// icon: detailWeatherData.weatherinfomation[indexPath.row].weatherIconImage, -// temp: detailWeatherData.weatherinfomation[indexPath.row].tempText) -// return cell -// -// } else if indexPath.section == 2 { -// let cell = WeeklyWeatherCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) -// cell.setData(week: weekWeatherData[indexPath.row].day, icon: weekWeatherData[indexPath.row].weatherIconImage, min: weekWeatherData[indexPath.row].minTempText, gradient: weekWeatherData[indexPath.row].gradientImage, max: weekWeatherData[indexPath.row].maxTempText) -// return cell -// } -// -// return UICollectionViewCell() -// } -// -// func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { -// if kind == UICollectionView.elementKindSectionHeader { -// let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HeaderView.reuseId, for: indexPath) as! HeaderView -// if indexPath.section == 1 { -// -// let label = UILabel() -// label.text = "08:00~09:00에 강우 상태가, 18:00에 한때 흐린 상태가 예상됩니다." -// label.font = .sfProRegular18 -// label.textColor = .white -// label.numberOfLines = 3 -// -// headerView.addSubview(label) -// -// // 레이블의 제약조건 설정 (예: 스냅킷 라이브러리 사용) -// label.snp.makeConstraints { -// $0.top.equalToSuperview().inset(15) -// $0.leading.trailing.equalToSuperview().inset(16) -// } -// -// } else if indexPath.section == 2 { -// let iconImageView = UIImageView(image: UIImage(systemName: "calendar")?.withTintColor(.white.withAlphaComponent(0.3), renderingMode: .alwaysOriginal)) -// -// -// let label = UILabel() -// label.text = "10일간의 일기예보" -// label.font = .sfProMedium15 -// label.textColor = .white.withAlphaComponent(0.3) -// headerView.addSubViews(iconImageView, label) -// -// iconImageView.snp.makeConstraints { -// $0.top.equalToSuperview().offset(15) -// $0.leading.equalToSuperview().offset(15) -// $0.size.equalTo(24) -// } -// -// label.snp.makeConstraints { -// $0.centerY.equalTo(iconImageView) -// $0.leading.equalTo(iconImageView.snp.trailing).offset(5) -// } -// } -// return headerView -// } -// return UICollectionReusableView() -// } -// -//}