diff --git a/Havit/Havit.xcodeproj/project.pbxproj b/Havit/Havit.xcodeproj/project.pbxproj index ca21f49a..2ecb90df 100644 --- a/Havit/Havit.xcodeproj/project.pbxproj +++ b/Havit/Havit.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ 15F6403327995E3700D9654E /* CategoryContentsServiceable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F6403227995E3700D9654E /* CategoryContentsServiceable.swift */; }; 15F6403727995EA400D9654E /* CategoryContentsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F6403627995EA400D9654E /* CategoryContentsService.swift */; }; 15F6403927995EE100D9654E /* CategoryContentsEndPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F6403827995EE100D9654E /* CategoryContentsEndPoint.swift */; }; + 15F6403B279B40F200D9654E /* CategoryContentEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F6403A279B40F200D9654E /* CategoryContentEmptyView.swift */; }; + 15F6403C279BAC0B00D9654E /* CreateContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FCB5FE2279B783600C196C9 /* CreateContent.swift */; }; 3BBB51D4279062910098A835 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBB51D3279062910098A835 /* WebKit.framework */; }; 3BBB51DA2794023E0098A835 /* WebViewToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BBB51D92794023E0098A835 /* WebViewToolbar.swift */; }; 4D2D21D4279AFFAE000D58AA /* AddCategoryTitleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F81AE172797E97D00336AFE /* AddCategoryTitleViewController.swift */; }; @@ -162,7 +164,6 @@ 4FC6EC642798A970000BD4E0 /* CategoryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DD166FC2796D0C900AD8960 /* CategoryService.swift */; }; 4FC6EC682798AE38000BD4E0 /* ShareCategoryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FC6EC672798AE38000BD4E0 /* ShareCategoryCollectionViewCell.swift */; }; 4FCB5FE3279B783600C196C9 /* CreateContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FCB5FE2279B783600C196C9 /* CreateContent.swift */; }; - 4FCB5FE4279B783800C196C9 /* CreateContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FCB5FE2279B783600C196C9 /* CreateContent.swift */; }; 4FD534CF27994604000C7034 /* SaveContentsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD534CE27994604000C7034 /* SaveContentsViewController.swift */; }; 4FD534D127996BDB000C7034 /* EditContentsTitleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD534D027996BDB000C7034 /* EditContentsTitleViewController.swift */; }; 4FD534D427997E21000C7034 /* SetAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD534D327997E21000C7034 /* SetAlertViewController.swift */; }; @@ -326,6 +327,7 @@ 15F6403227995E3700D9654E /* CategoryContentsServiceable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryContentsServiceable.swift; sourceTree = ""; }; 15F6403627995EA400D9654E /* CategoryContentsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryContentsService.swift; sourceTree = ""; }; 15F6403827995EE100D9654E /* CategoryContentsEndPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryContentsEndPoint.swift; sourceTree = ""; }; + 15F6403A279B40F200D9654E /* CategoryContentEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryContentEmptyView.swift; sourceTree = ""; }; 3BBB51D3279062910098A835 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 3BBB51D92794023E0098A835 /* WebViewToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewToolbar.swift; sourceTree = ""; }; 4D4DDD4627912AE10069F5FB /* CategoryIconList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryIconList.swift; sourceTree = ""; }; @@ -532,6 +534,7 @@ children = ( 1546A3F82797F998009AE579 /* CategoryContentsEnum.swift */, 1546A3FA2797FA9C009AE579 /* Cells */, + 15F6403A279B40F200D9654E /* CategoryContentEmptyView.swift */, ); path = Components; sourceTree = ""; @@ -1529,7 +1532,7 @@ 4FB24FD9279217D300CCDB0C /* BaseCollectionViewCell.swift in Sources */, 4FD534D427997E21000C7034 /* SetAlertViewController.swift in Sources */, 4FB24FE02792180100CCDB0C /* UIView+Extension.swift in Sources */, - 4FCB5FE4279B783800C196C9 /* CreateContent.swift in Sources */, + 15F6403C279BAC0B00D9654E /* CreateContent.swift in Sources */, 4F40456C279B6D7000103AC7 /* CategoryContentsServiceable.swift in Sources */, 4FB24FE32792180B00CCDB0C /* UIButton+Extension.swift in Sources */, 4F4545F12791B3CD00A9E3B1 /* BaseViewController.swift in Sources */, @@ -1674,6 +1677,7 @@ ED443F1F2786A4060059DE76 /* CategoryViewModel.swift in Sources */, EDEF618B2790C2AC00C93C84 /* SearchBarView.swift in Sources */, EDEF6191279136DD00C93C84 /* HttpMethod.swift in Sources */, + 15F6403B279B40F200D9654E /* CategoryContentEmptyView.swift in Sources */, ED443EB0278598670059DE76 /* SceneDelegate.swift in Sources */, 1546A40627984EF9009AE579 /* SearchContentsService.swift in Sources */, ED443F462786B99B0059DE76 /* UIViewController+Extension.swift in Sources */, diff --git a/Havit/Havit/Screens/CategoryContents/View/CategoryContentsViewController.swift b/Havit/Havit/Screens/CategoryContents/View/CategoryContentsViewController.swift index 1d55e732..f1de5c3b 100644 --- a/Havit/Havit/Screens/CategoryContents/View/CategoryContentsViewController.swift +++ b/Havit/Havit/Screens/CategoryContents/View/CategoryContentsViewController.swift @@ -24,8 +24,6 @@ final class CategoryContentsViewController: BaseViewController { environment: .development) var categoryContents: [Content] = [] - var categoryContentsIsEmpty: CategoryContentsIsEmpty = .noEmpty - var isFromAllCategory: Bool = false private var gridAnd1XnConstraints: Constraint? @@ -162,6 +160,9 @@ final class CategoryContentsViewController: BaseViewController { return button }() + private let emptyView = MainContentEmptyView(guideText: + "아직 저장된 콘텐츠가 없습니다.", isCategoryContentView: true) + // MARK: - init init(categoryId: Int, categories: [Category]) { @@ -180,8 +181,8 @@ final class CategoryContentsViewController: BaseViewController { override func viewDidLoad() { super.viewDidLoad() - print(categories) - print(categoryId) + dump(categories) + dump(categoryId) bind() getCategoryContents() setDelegations() @@ -193,8 +194,9 @@ final class CategoryContentsViewController: BaseViewController { } override func render() { - self.view.addSubViews([mainView, filterView]) - mainView.addSubViews([mainViewBorderView, contentsCollectionView]) + self.view.addSubView(mainView) + mainView.addSubViews([filterView, mainViewBorderView, emptyView]) + emptyView.addSubView(contentsCollectionView) filterView.addSubViews([totalLabel, gridButton, sortButton, filterCollectionView]) mainView.snp.makeConstraints { @@ -209,11 +211,16 @@ final class CategoryContentsViewController: BaseViewController { } mainViewBorderView.snp.makeConstraints { - $0.leading.trailing.equalTo(mainView) + $0.leading.trailing.equalToSuperview() $0.top.equalTo(filterView.snp.bottom) $0.height.equalTo(1) } + emptyView.snp.makeConstraints { + $0.top.equalTo(mainViewBorderView.snp.bottom) + $0.leading.trailing.bottom.equalToSuperview() + } + totalLabel.snp.makeConstraints { $0.leading.equalTo(filterView).offset(16) $0.top.equalTo(filterView) @@ -306,11 +313,9 @@ final class CategoryContentsViewController: BaseViewController { !categoryContents.isEmpty { self.categoryContents = categoryContents self.totalLabel.text = "전체 \(categoryContents.count)" - self.categoryContentsIsEmpty = .noEmpty } else { self.categoryContents = [] self.totalLabel.text = "전체 0" - self.categoryContentsIsEmpty = .empty } } else { if let nowCategory = getNowCategory(), let id = nowCategory.id { @@ -319,16 +324,15 @@ final class CategoryContentsViewController: BaseViewController { !categoryContents.isEmpty { self.categoryContents = categoryContents self.totalLabel.text = "전체 \(categoryContents.count)" - self.categoryContentsIsEmpty = .noEmpty } else { self.categoryContents = [] self.totalLabel.text = "전체 0" - self.categoryContentsIsEmpty = .empty } } } DispatchQueue.main.async { + self.updateCollectionViewEmptyState() self.contentsCollectionView.reloadData() } } catch APIServiceError.serverError { @@ -372,6 +376,12 @@ final class CategoryContentsViewController: BaseViewController { navigationItem.leftBarButtonItem = makeBarButtonItem(with: backButton) } + func updateCollectionViewEmptyState() { + let isContentEmpty = categoryContents.isEmpty + + contentsCollectionView.isHidden = isContentEmpty + } + private func setDelegations() { filterCollectionView.delegate = self filterCollectionView.dataSource = self @@ -482,10 +492,9 @@ final class CategoryContentsViewController: BaseViewController { } @objc func changeContentsShow(_ sender: UIButton) { - switch categoryContentsIsEmpty { - case .empty: - fallthrough - case .noEmpty: + let hasContent = !categoryContents.isEmpty + + if hasContent { switch gridType { case .grid: gridType = .grid2xN @@ -534,10 +543,9 @@ extension CategoryContentsViewController: UICollectionViewDelegate { contentsFilterType = cell.contentsFilterType getCategoryContents() case contentsCollectionView: - switch categoryContentsIsEmpty { - case .empty: - fallthrough - case .noEmpty: + let hasContent = !categoryContents.isEmpty + + if hasContent { let item = indexPath.item if let url = categoryContents[item].url, let isReadContent = categoryContents[item].isSeen, @@ -584,52 +592,44 @@ extension CategoryContentsViewController: UICollectionViewDataSource { cell.layer.masksToBounds = true return cell case contentsCollectionView: - switch categoryContentsIsEmpty { - case .empty: - let cell: NotSearchedCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - cell.imageView.image = UIImage(named: "imgSearch") - cell.noResultLabel.isHidden = false + switch gridType { + case .grid: + let cell: ContentsCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) + cell.backgroundColor = .white + cell.update(content: categoryContents[indexPath.item]) + cell.didTapIsReadButton = { [weak self] contentId, item in + self?.patchContentToggle(contentId: contentId, item: item) + } + if categoryContents[indexPath.row].isNotified == true { + cell.alarmImageView.isHidden = false + } + cell.moreButton.addTarget(self, action: #selector(showMorePanModalViewController(_:)), for: .touchUpInside) return cell - case .noEmpty: - switch gridType { - case .grid: - let cell: ContentsCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - cell.backgroundColor = .white - cell.update(content: categoryContents[indexPath.item]) - cell.didTapIsReadButton = { [weak self] contentId, item in - self?.patchContentToggle(contentId: contentId, item: item) - } - if categoryContents[indexPath.row].isNotified == true { - cell.alarmImageView.isHidden = false - } - cell.moreButton.addTarget(self, action: #selector(showMorePanModalViewController(_:)), for: .touchUpInside) - return cell - case .grid2xN: - let cell: CategoryContents2xNCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - cell.backgroundColor = .white - contentsCollectionView.backgroundColor = .white - cell.update(content: categoryContents[indexPath.item]) - cell.didTapIsReadButton = { [weak self] contentId, item in - self?.patchContentToggleGrid2xN(contentId: contentId, item: item) - } - if categoryContents[indexPath.row].isNotified == true { - cell.alarmImageView.isHidden = false - } - cell.moreButton.addTarget(self, action: #selector(showMorePanModalViewController(_:)), for: .touchUpInside) - return cell - case .grid1xN: - let cell: CategoryContents1xNCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - cell.backgroundColor = .white - cell.update(content: categoryContents[indexPath.item]) - cell.didTapIsReadButton = { [weak self] contentId, item in - self?.patchContentToggleGrid1xN(contentId: contentId, item: item) - } - if categoryContents[indexPath.row].isNotified == true { - cell.alarmImageView.isHidden = false - } - cell.moreButton.addTarget(self, action: #selector(showMorePanModalViewController(_:)), for: .touchUpInside) - return cell + case .grid2xN: + let cell: CategoryContents2xNCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) + cell.backgroundColor = .white + contentsCollectionView.backgroundColor = .white + cell.update(content: categoryContents[indexPath.item]) + cell.didTapIsReadButton = { [weak self] contentId, item in + self?.patchContentToggleGrid2xN(contentId: contentId, item: item) + } + if categoryContents[indexPath.row].isNotified == true { + cell.alarmImageView.isHidden = false + } + cell.moreButton.addTarget(self, action: #selector(showMorePanModalViewController(_:)), for: .touchUpInside) + return cell + case .grid1xN: + let cell: CategoryContents1xNCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) + cell.backgroundColor = .white + cell.update(content: categoryContents[indexPath.item]) + cell.didTapIsReadButton = { [weak self] contentId, item in + self?.patchContentToggleGrid1xN(contentId: contentId, item: item) } + if categoryContents[indexPath.row].isNotified == true { + cell.alarmImageView.isHidden = false + } + cell.moreButton.addTarget(self, action: #selector(showMorePanModalViewController(_:)), for: .touchUpInside) + return cell } default: return UICollectionViewCell() @@ -643,12 +643,7 @@ extension CategoryContentsViewController: UICollectionViewDelegateFlowLayout { case filterCollectionView: return 4 case contentsCollectionView: - switch categoryContentsIsEmpty { - case .empty: - return 1 - case .noEmpty: - return categoryContents.count - } + return categoryContents.count default: return 0 } @@ -670,18 +665,13 @@ extension CategoryContentsViewController: UICollectionViewDelegateFlowLayout { return CGSize(width: label.frame.width + 28, height: 31) } case contentsCollectionView: - switch categoryContentsIsEmpty { - case .empty: - return CGSize(width: view.frame.width, height: (mainView.frame.size.height - 15) / 2) - case .noEmpty: - switch gridType { - case .grid: - return CGSize(width: view.frame.width, height: 139) - case .grid2xN: - return CGSize(width: (view.frame.width / 2) - 20, height: 253) - case .grid1xN: - return CGSize(width: view.frame.width, height: 307) - } + switch gridType { + case .grid: + return CGSize(width: view.frame.width, height: 139) + case .grid2xN: + return CGSize(width: (view.frame.width / 2) - 20, height: 253) + case .grid1xN: + return CGSize(width: view.frame.width, height: 307) } default: return CGSize(width: 0, height: 0) diff --git a/Havit/Havit/Screens/CategoryContents/View/Components/CategoryContentEmptyView.swift b/Havit/Havit/Screens/CategoryContents/View/Components/CategoryContentEmptyView.swift new file mode 100644 index 00000000..0694a6d1 --- /dev/null +++ b/Havit/Havit/Screens/CategoryContents/View/Components/CategoryContentEmptyView.swift @@ -0,0 +1,20 @@ +// +// CategoryContentEmptyView.swift +// Havit +// +// Created by 박예빈 on 2022/01/22. +// + +import UIKit + +class CategoryContentEmptyView: UIView { + + /* + // Only override draw() if you perform custom drawing. + // An empty implementation adversely affects performance during animation. + override func draw(_ rect: CGRect) { + // Drawing code + } + */ + +} diff --git a/Havit/Havit/Screens/Main/View/Cell/RecentContentCollectionViewCell.swift b/Havit/Havit/Screens/Main/View/Cell/RecentContentCollectionViewCell.swift index ba2e223b..7296f261 100644 --- a/Havit/Havit/Screens/Main/View/Cell/RecentContentCollectionViewCell.swift +++ b/Havit/Havit/Screens/Main/View/Cell/RecentContentCollectionViewCell.swift @@ -95,7 +95,13 @@ final class RecentContentCollectionViewCell: BaseCollectionViewCell { dateLabel.text = changeDateFormat(with: createdAt) } - if let title = content.title { + if var title = content.title { + if title.count > 10 { + let title1 = title.components(separatedBy: " ")[0] + let title2 = title.components(separatedBy: " ")[1] + + title = "\(title1) \(title2)" + } buttonConfiguration.attributedTitle = AttributedString(title, attributes: buttonContainer) categoryTagButton.configuration = buttonConfiguration } diff --git a/Havit/Havit/Screens/Main/View/Component/MainContentEmptyView.swift b/Havit/Havit/Screens/Main/View/Component/MainContentEmptyView.swift index 533967ac..f9092d3e 100644 --- a/Havit/Havit/Screens/Main/View/Component/MainContentEmptyView.swift +++ b/Havit/Havit/Screens/Main/View/Component/MainContentEmptyView.swift @@ -36,10 +36,13 @@ final class MainContentEmptyView: UIView { button.layer.cornerRadius = 24 return button }() + + private var isCategoryContentView: Bool // MARK: - init - init(guideText: String) { + init(guideText: String, isCategoryContentView: Bool = false) { + self.isCategoryContentView = isCategoryContentView super.init(frame: .zero) titleLabel.text = guideText render() @@ -70,7 +73,7 @@ final class MainContentEmptyView: UIView { createContentButton.snp.makeConstraints { $0.centerX.equalToSuperview() - $0.top.equalTo(noContentImageView.snp.bottom).offset(78) + $0.top.equalTo(noContentImageView.snp.bottom).offset(isCategoryContentView ? 30 : 78) $0.width.equalTo(233) $0.height.equalTo(48) }