diff --git a/.DS_Store b/.DS_Store index 0b74d4a2..d04750a3 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 0625c60d..5776d5f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store *.xcuserstate -APIKey.plist \ No newline at end of file +APIKey.plist +BoxOffice.xcodeproj/xcuserdata/redmango1446.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/BoxOffice.xcodeproj/project.pbxproj b/BoxOffice.xcodeproj/project.pbxproj index 5e8f2777..912fb320 100644 --- a/BoxOffice.xcodeproj/project.pbxproj +++ b/BoxOffice.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 5D2CF6C92A8B6F0A009EECB3 /* CollectionViewIconCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D2CF6C72A8B6F0A009EECB3 /* CollectionViewIconCell.swift */; }; + 5D2CF6CA2A8B6F0A009EECB3 /* CollectionViewIconCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5D2CF6C82A8B6F0A009EECB3 /* CollectionViewIconCell.xib */; }; 5D4FAA982A6E8604001FA74A /* BoxOfficeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D4FAA972A6E8604001FA74A /* BoxOfficeTests.swift */; }; 5D4FAAA12A6E88D3001FA74A /* box_office_sample.json in Resources */ = {isa = PBXBuildFile; fileRef = 5D4FAAA02A6E88D2001FA74A /* box_office_sample.json */; }; 5DDFC3282A72628700135954 /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DDFC3272A72628700135954 /* Movie.swift */; }; @@ -29,6 +31,7 @@ D0989F712A77616400716556 /* APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0989F702A77616400716556 /* APIError.swift */; }; D0989F882A7B517900716556 /* APIKey.plist in Resources */ = {isa = PBXBuildFile; fileRef = D0989F872A7B517900716556 /* APIKey.plist */; }; D0989F8A2A7B522400716556 /* HideAPIKey++Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0989F892A7B522400716556 /* HideAPIKey++Bundle.swift */; }; + D0F060152A8C96DF006133E4 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F060142A8C96DF006133E4 /* Arrow.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,6 +45,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5D2CF6C72A8B6F0A009EECB3 /* CollectionViewIconCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewIconCell.swift; sourceTree = ""; }; + 5D2CF6C82A8B6F0A009EECB3 /* CollectionViewIconCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CollectionViewIconCell.xib; sourceTree = ""; }; 5D4FAA952A6E8604001FA74A /* BoxOfficeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoxOfficeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5D4FAA972A6E8604001FA74A /* BoxOfficeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxOfficeTests.swift; sourceTree = ""; }; 5D4FAAA02A6E88D2001FA74A /* box_office_sample.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = box_office_sample.json; sourceTree = ""; }; @@ -67,6 +72,7 @@ D0989F702A77616400716556 /* APIError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIError.swift; sourceTree = ""; }; D0989F872A7B517900716556 /* APIKey.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = APIKey.plist; sourceTree = ""; }; D0989F892A7B522400716556 /* HideAPIKey++Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HideAPIKey++Bundle.swift"; sourceTree = ""; }; + D0F060142A8C96DF006133E4 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -193,6 +199,7 @@ children = ( 63DF20F42970E1A0005DF7D1 /* Main.storyboard */, 5DDFC35A2A79FBEB00135954 /* CollectionViewListCell.xib */, + 5D2CF6C82A8B6F0A009EECB3 /* CollectionViewIconCell.xib */, 63DF20F92970E1A1005DF7D1 /* LaunchScreen.storyboard */, ); path = View; @@ -214,14 +221,24 @@ D06DF27F2A6E737D0074F9EF /* Controller */ = { isa = PBXGroup; children = ( + D0F060162A8C9782006133E4 /* Enum */, D0246A132A81E4B70045C0B6 /* Protocol+ */, 63DF20F22970E1A0005DF7D1 /* MainViewController.swift */, D0246A0F2A81DDC50045C0B6 /* CalendarViewController.swift */, 5DDFC3592A79FBEB00135954 /* CollectionViewListCell.swift */, + 5D2CF6C72A8B6F0A009EECB3 /* CollectionViewIconCell.swift */, ); path = Controller; sourceTree = ""; }; + D0F060162A8C9782006133E4 /* Enum */ = { + isa = PBXGroup; + children = ( + D0F060142A8C96DF006133E4 /* Arrow.swift */, + ); + path = Enum; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -311,6 +328,7 @@ buildActionMask = 2147483647; files = ( 63DF20FB2970E1A1005DF7D1 /* LaunchScreen.storyboard in Resources */, + 5D2CF6CA2A8B6F0A009EECB3 /* CollectionViewIconCell.xib in Resources */, 63DF20F82970E1A1005DF7D1 /* Assets.xcassets in Resources */, 63DF20F62970E1A0005DF7D1 /* Main.storyboard in Resources */, D0989F882A7B517900716556 /* APIKey.plist in Resources */, @@ -341,11 +359,13 @@ 5DDFC38E2A83881500135954 /* DateProviderError.swift in Sources */, 5DDFC3282A72628700135954 /* Movie.swift in Sources */, 5DDFC35E2A7A61A400135954 /* DateProvider.swift in Sources */, + 5D2CF6C92A8B6F0A009EECB3 /* CollectionViewIconCell.swift in Sources */, 5DDFC32A2A735C0100135954 /* URLManager.swift in Sources */, D040BE3D2A713E86007F2095 /* APIManager.swift in Sources */, D06DF2812A6E73B40074F9EF /* BoxOffice.swift in Sources */, D0246A102A81DDC50045C0B6 /* CalendarViewController.swift in Sources */, 63DF20F32970E1A0005DF7D1 /* MainViewController.swift in Sources */, + D0F060152A8C96DF006133E4 /* Arrow.swift in Sources */, 63DF20EF2970E1A0005DF7D1 /* AppDelegate.swift in Sources */, D0989F712A77616400716556 /* APIError.swift in Sources */, 63DF20F12970E1A0005DF7D1 /* SceneDelegate.swift in Sources */, diff --git a/BoxOffice.xcodeproj/xcuserdata/redmango1446.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/BoxOffice.xcodeproj/xcuserdata/redmango1446.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index d820562e..00000000 --- a/BoxOffice.xcodeproj/xcuserdata/redmango1446.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BoxOffice/Controller/CollectionViewIconCell.swift b/BoxOffice/Controller/CollectionViewIconCell.swift new file mode 100644 index 00000000..697beaff --- /dev/null +++ b/BoxOffice/Controller/CollectionViewIconCell.swift @@ -0,0 +1,89 @@ +// +// CollectionViewIconCell.swift +// BoxOffice +// +// Created by redmango1446 on 2023/08/15. +// + +import UIKit + +class CollectionViewIconCell: UICollectionViewCell { + @IBOutlet weak var rankNumberLabel: UILabel! + @IBOutlet weak var movieNameLabel: UILabel! + @IBOutlet weak var rankInfoLabel: UILabel! + @IBOutlet weak var audiNumberLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + + } + + override func layoutSubviews() { + super.layoutSubviews() + self.layer.borderWidth = 1 + self.layer.borderColor = UIColor.black.cgColor + self.layer.cornerRadius = 10 + } + + func configureFont() { + rankNumberLabel.font = .preferredFont(forTextStyle: .title1) + rankInfoLabel.font = .preferredFont(forTextStyle: .body) + audiNumberLabel.font = .preferredFont(forTextStyle: .body) + audiNumberLabel.adjustsFontSizeToFitWidth = true + movieNameLabel.font = .preferredFont(forTextStyle: .title3) + movieNameLabel.allowsDefaultTighteningForTruncation = true + movieNameLabel.numberOfLines = 2 + } + + func configureDynamicType() { + rankNumberLabel.adjustsFontForContentSizeCategory = true + rankInfoLabel.adjustsFontForContentSizeCategory = true + movieNameLabel.adjustsFontForContentSizeCategory = true + audiNumberLabel.adjustsFontForContentSizeCategory = true + } + + func configureLabels(with dailyBoxOffice: DailyBoxOffice) { + configureAudiNumberLabel(with: dailyBoxOffice) + configureRankInfoLabel(with: dailyBoxOffice) + rankNumberLabel.text = dailyBoxOffice.rank + movieNameLabel.text = dailyBoxOffice.movieName + } + + func configureAudiNumberLabel(with dailyBoxOffice: DailyBoxOffice) { + let numberFormatter = NumberFormatter() + numberFormatter.numberStyle = .decimal + + guard let audiCnt = Int(dailyBoxOffice.audiCnt), + let formattedAudiCnt = numberFormatter.string(from: NSNumber(value: audiCnt)) else { return } + + guard let audiAcc = Int(dailyBoxOffice.audiAcc), + let formattedAudiAcc = numberFormatter.string(from: NSNumber(value: audiAcc)) else { return } + + audiNumberLabel.text = "오늘 \(formattedAudiCnt) / 총 \(formattedAudiAcc)" + } + + func configureRankInfoLabel(with dailyBoxOffice: DailyBoxOffice) { + switch dailyBoxOffice.rankOldAndNew { + case "NEW": + rankInfoLabel.textColor = .red + rankInfoLabel.text = "신작" + case "OLD": + if dailyBoxOffice.rankInten == "0" { + rankInfoLabel.text = "-" + return + } + + if let rankInten = Int(dailyBoxOffice.rankInten), + let arrow = Arrow(rawValue: rankInten) { + rankInfoLabel.textColor = .black + let rankIntenString = "\(arrow.rawValue)\(abs(rankInten))" + let attributedString = NSMutableAttributedString(string: rankIntenString) + let range = (rankIntenString as NSString).range(of: arrow.rawValue) + attributedString.addAttribute(.foregroundColor, value: arrow.color, range: range) + rankInfoLabel.attributedText = attributedString + } + default: + print("no Data") + } + } +} diff --git a/BoxOffice/Controller/CollectionViewListCell.swift b/BoxOffice/Controller/CollectionViewListCell.swift index daf7bd83..b0b3f980 100644 --- a/BoxOffice/Controller/CollectionViewListCell.swift +++ b/BoxOffice/Controller/CollectionViewListCell.swift @@ -18,9 +18,17 @@ final class CollectionViewListCell: UICollectionViewListCell { } func configureFont() { - rankNumberLabel.font = UIFont.systemFont(ofSize: 30) - rankInfoLabel.font = UIFont.systemFont(ofSize: 15) - audiNumberLabel.font = UIFont.systemFont(ofSize: 15) + rankNumberLabel.font = .preferredFont(forTextStyle: .title1) + rankInfoLabel.font = .preferredFont(forTextStyle: .caption1) + movieNameLabel.font = .preferredFont(forTextStyle: .title3) + audiNumberLabel.font = .preferredFont(forTextStyle: .caption1) + } + + func configureDynamicType() { + rankNumberLabel.adjustsFontForContentSizeCategory = true + rankInfoLabel.adjustsFontForContentSizeCategory = true + movieNameLabel.adjustsFontForContentSizeCategory = true + audiNumberLabel.adjustsFontForContentSizeCategory = true } func configureLabels(with dailyBoxOffice: DailyBoxOffice) { @@ -50,6 +58,7 @@ final class CollectionViewListCell: UICollectionViewListCell { rankInfoLabel.text = "신작" case "OLD": if dailyBoxOffice.rankInten == "0" { + rankInfoLabel.textColor = .black rankInfoLabel.text = "-" return } @@ -68,24 +77,3 @@ final class CollectionViewListCell: UICollectionViewListCell { } } } - -extension CollectionViewListCell { - enum Arrow: String { - case upArrow = "▲" - case downArrow = "▼" - - var color: UIColor { - switch self { - case .upArrow: - return .red - case .downArrow: - return .blue - } - } - - init?(rawValue: Int) { - self = rawValue > 0 ? .upArrow : .downArrow - } - } -} - diff --git a/BoxOffice/Controller/Enum/Arrow.swift b/BoxOffice/Controller/Enum/Arrow.swift new file mode 100644 index 00000000..c74be6b3 --- /dev/null +++ b/BoxOffice/Controller/Enum/Arrow.swift @@ -0,0 +1,26 @@ +// +// Arrow.swift +// BoxOffice +// +// Created by 박종화 on 2023/08/16. +// + +import UIKit + +enum Arrow: String { + case upArrow = "▲" + case downArrow = "▼" + + var color: UIColor { + switch self { + case .upArrow: + return .red + case .downArrow: + return .blue + } + } + + init?(rawValue: Int) { + self = rawValue > 0 ? .upArrow : .downArrow + } +} diff --git a/BoxOffice/Controller/MainViewController.swift b/BoxOffice/Controller/MainViewController.swift index 053def1e..a9ba58c4 100644 --- a/BoxOffice/Controller/MainViewController.swift +++ b/BoxOffice/Controller/MainViewController.swift @@ -11,7 +11,13 @@ final class MainViewController: UIViewController, CalendarViewControllerDelegate @IBOutlet weak var collectionView: UICollectionView! @IBOutlet weak var loadingActivityView: UIActivityIndicatorView! @IBOutlet weak var calendarButton: UIButton! + @IBOutlet weak var changeModeButton: UIButton! var boxOffice: BoxOffice? + var isIconMode: Bool = false { + willSet(newVal){ + changeLayout(newValue: newVal) + } + } override func viewDidLoad() { super.viewDidLoad() @@ -19,10 +25,56 @@ final class MainViewController: UIViewController, CalendarViewControllerDelegate assignDataSourceAndDelegate() registerCustomCell() callAPIManager() + configureListLayout() configureTitle() initRefresh() } + private func configureFlowLayout() { + let layout = UICollectionViewFlowLayout() + collectionView.setCollectionViewLayout(layout, animated: false) + } + + private func configureListLayout() { + let configuration = UICollectionLayoutListConfiguration(appearance: .plain) + let layout = UICollectionViewCompositionalLayout.list(using: configuration) + collectionView.setCollectionViewLayout(layout, animated: false) + } + + private func changeLayout(newValue: Bool) { + if newValue == true { + configureFlowLayout() + } else { + configureListLayout() + } + } + + @IBAction func tapChangeModeButton(_ sender: Any) { + let actionSheet = UIAlertController(title: "화면모드변경", message: nil, preferredStyle: .actionSheet) + + let icon = UIAlertAction(title: "아이콘", style: .default) { action in + self.isIconMode = true + self.collectionView.reloadData() + } + + let list = UIAlertAction(title: "리스트", style: .default) { action in + self.isIconMode = false + self.collectionView.reloadData() + } + + let cancel = UIAlertAction(title: "취소", style: .cancel) + + if isIconMode { + actionSheet.addAction(list) + } else { + actionSheet.addAction(icon) + } + + actionSheet.addAction(cancel) + + present(actionSheet, animated: true, completion: nil) + } + private func showLodingView() { collectionView.isHidden = true loadingActivityView.startAnimating() @@ -70,7 +122,9 @@ final class MainViewController: UIViewController, CalendarViewControllerDelegate private func registerCustomCell() { collectionView.register(UINib(nibName: "CollectionViewListCell", bundle: nil), - forCellWithReuseIdentifier: "cell") + forCellWithReuseIdentifier: "listCell") + collectionView.register(UINib(nibName: "CollectionViewIconCell", bundle: nil), + forCellWithReuseIdentifier: "iconCell") } @objc private func updateData() { @@ -115,23 +169,67 @@ extension MainViewController: UICollectionViewDataSource { } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? CollectionViewListCell else { return UICollectionViewListCell() } - - if let boxOfficeData = boxOffice { - let dailyBoxOffice = boxOfficeData.boxOfficeResult.dailyBoxOfficeList[indexPath.item] - cell.configureLabels(with: dailyBoxOffice) - cell.configureFont() - cell.accessories = [.disclosureIndicator()] + if isIconMode { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "iconCell", for: indexPath) as? CollectionViewIconCell else { return UICollectionViewCell() } + + if let boxOfficeData = boxOffice { + let dailyBoxOffice = boxOfficeData.boxOfficeResult.dailyBoxOfficeList[indexPath.item] + cell.configureLabels(with: dailyBoxOffice) + cell.configureFont() + cell.configureDynamicType() + } + + return cell + } else { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as? CollectionViewListCell else { return UICollectionViewListCell() } + + if let boxOfficeData = boxOffice { + let dailyBoxOffice = boxOfficeData.boxOfficeResult.dailyBoxOfficeList[indexPath.item] + cell.configureLabels(with: dailyBoxOffice) + cell.configureFont() + cell.configureDynamicType() + cell.accessories = [.disclosureIndicator()] + } + + return cell } - - return cell } } extension MainViewController: UICollectionViewDelegate { - func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) { + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard let pushMovieDetailVC = self.storyboard?.instantiateViewController(withIdentifier: "MovieDetailViewController") else { return } self.navigationController?.pushViewController(pushMovieDetailVC, animated: true) } } + +extension MainViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let viewWidth = collectionView.bounds.width + let viewHeight = collectionView.bounds.height + + if isIconMode { + let cellWidth = (viewWidth - 20 * 3) / 2 + return CGSize(width: cellWidth, height: cellWidth) + } else { + return CGSize(width: viewWidth, height: viewHeight / 9) + } + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + if isIconMode { + return UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) + } else { + return UIEdgeInsets.zero + } + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + if isIconMode { + return 10 + } else { + return 1 + } + } +} diff --git a/BoxOffice/View/Base.lproj/Main.storyboard b/BoxOffice/View/Base.lproj/Main.storyboard index 04080817..fbca282d 100644 --- a/BoxOffice/View/Base.lproj/Main.storyboard +++ b/BoxOffice/View/Base.lproj/Main.storyboard @@ -2,7 +2,6 @@ - @@ -23,9 +22,12 @@ - - - + + + + + + @@ -46,19 +48,28 @@ + - + + -